Constructing a New Public API
This yr, I launched into an thrilling journey to construct a brand new public API system for certainly one of my shoppers. The purpose was to create a system permitting them to promote entry to their priceless dataset to exterior events. This mission wasn’t nearly opening up new income streams; it was about innovation and increasing the worth we may provide to the shoppers sector.
APIs play an important function in fashionable software program techniques, facilitating the circulate of important information throughout varied parts and platforms. By enabling third events to construct merchandise on high of our infrastructure, we had been set to considerably improve the platform’s worth and attain.
However our imaginative and prescient prolonged past exterior use. We aimed to create an API that will additionally function an inside normal for information entry throughout the platform. This dual-purpose method promised to streamline operations and set a brand new benchmark for effectivity.
Constructing the Infrastructure
Beginning such a mission may be daunting, however I’ve realized that the act of starting is commonly probably the most essential milestone. Upon getting one thing tangible, it turns into a lot simpler to iterate and enhance. Nevertheless, earlier than diving into coding, I knew that designing the proper infrastructure from the beginning could be half the battle. The previous adage “measure twice, reduce as soon as” got here to thoughts.
My focus was on three key areas:
- Applied sciences: Selecting the best tech stack
- Construction: Guaranteeing maintainability by means of correct mission group
- Safety: Implementing sturdy measures to guard the primary platform
Applied sciences
Provided that the primary platform runs on .NET 5/6+, I made a decision to leverage this know-how as the inspiration for the brand new API system. This resolution instantly descoped a big quantity of effort – a crucial consideration for a solo developer.
I additionally wished to include Swagger with its OpenAPI specification, instruments I might had optimistic experiences with prior to now. These two key applied sciences fashioned the bottom upon which I constructed the remainder of the stack.
The ultimate tech stack included:
- .NET
- Swagger + OpenAPI specification
- Microsoft SQL Server
- Docker
- Microsoft entity framework
Venture Construction
For the mission construction, I opted to create a brand new space throughout the present answer quite than a separate .sln
file. This method maintains a cohesive view of your entire codebase, which is especially useful for smaller groups.
I began by defining the routes for the preliminary model of the API:
/api/v2/campuses
/api/v2/campuses/[id]
/api/v2/programs
/api/v2/programs/[id]
/api/v2/intakes
/api/v2/intakes/[id]
/api/v2/suppliers
/api/v2/suppliers/[id]
Primarily based on these routes, I created the next listing construction:
PublicApi/
├── Controllers/
│ ├── CampusesController.cs
│ ├── CoursesController.cs
│ ├── IntakesController.cs
│ ├── ProviderController.cs
│ └── ScholarshipController.cs
├── Fashions/
│ ├── Campus.cs
│ ├── Course.cs
│ ├── Consumption.cs
│ ├── Supplier.cs
│ └── Scholarship.cs
└── Providers/
(initially empty, to be populated as wanted)
I started by defining the fashions that formed the API’s response payloads. With these in place, I may then arrange primary GET endpoints for each record and particular person useful resource retrieval, initially returning dummy information.
Here is a primary instance of one of many domain-driven endpoints:
utilizing System.Collections.Generic;
namespace PublicApi.Fashions
public class Course
public string Title get; set;
public string Id get; set;
public string ProviderId get; set;
public string LevelOfStudy get; set;
public Checklist AreasOfStudy get; set;
public Checklist SubjectsOfStudy get; set;
public string Particulars get; set;
public string EntryRequirements get; set;
public string Length get; set;
public bool Lively get; set;
public lengthy LastUpdated get; set;
public bool InternationalFlag get; set;
// Dummy data for illustration
var courses = new List
new Course
Name=”Computer Science”,
Id = ‘CS101’,
ProviderId = ‘UNIV001’,
LevelOfStudy = ‘Undergraduate’,
AreasOfStudy = new List
SubjectsOfStudy = new List
Details=”A comprehensive course covering the fundamentals of computer science.”,
EntryRequirements=”High school diploma with strong mathematics background”,
Duration = ‘4 years’,
Active = true,
LastUpdated = 1630444800,
InternationalFlag = true
,
new Course
Name=”Business Administration”,
Id = ‘BA201’,
ProviderId = ‘UNIV001’,
LevelOfStudy = ‘Graduate’,
AreasOfStudy = new List
SubjectsOfStudy = new List
Details=”An MBA program designed for aspiring business leaders.”,
EntryRequirements=”Bachelor”s degree and 2 years of work experience’,
Duration = ‘2 years’,
Active = true,
LastUpdated = 1641024000,
InternationalFlag = true
;
return Ok(courses);
[HttpGet(‘id’)]
public ActionResult
// Dummy information for illustration
var course = new Course
Title=”Information Science”,
Id = id,
ProviderId = ‘UNIV001’,
LevelOfStudy = ‘Graduate’,
AreasOfStudy = new Checklist
SubjectsOfStudy = new Checklist
Particulars=”A complicated course in information science and analytics.”,
EntryRequirements=”Bachelor”s diploma in a quantitative subject’,
Length = ‘2 years’,
Lively = true,
LastUpdated = 1651363200,
InternationalFlag = true
;
return Okay(course);
}
}” data-lang=”textual content/x-csharp”>
utilizing Microsoft.AspNetCore.Mvc;
utilizing System.Collections.Generic;
utilizing PublicApi.Fashions;
namespace PublicApi.Controllers
{
[Area("PublicApi")]
[ApiController]
[Route("api/v2/[controller]")]
[ApiExplorerSettings(GroupName = "PublicApi")]
public class CoursesController : ControllerBase
{
[HttpGet]
public ActionResult> GetCourses()
// Dummy information for illustration
var programs = new Checklist
new Course
Title = "Laptop Science",
Id = "CS101",
ProviderId = "UNIV001",
LevelOfStudy = "Undergraduate",
AreasOfStudy = new Checklist "Expertise", "Arithmetic" ,
SubjectsOfStudy = new Checklist "Programming", "Algorithms", "Information Constructions" ,
Particulars = "A complete course masking the basics of laptop science.",
EntryRequirements = "Highschool diploma with sturdy arithmetic background",
Length = "4 years",
Lively = true,
LastUpdated = 1630444800,
InternationalFlag = true
,
new Course
Title = "Enterprise Administration",
Id = "BA201",
ProviderId = "UNIV001",
LevelOfStudy = "Graduate",
AreasOfStudy = new Checklist "Enterprise", "Administration" ,
SubjectsOfStudy = new Checklist "Finance", "Advertising", "Operations" ,
Particulars = "An MBA program designed for aspiring enterprise leaders.",
EntryRequirements = "Bachelor's diploma and a couple of years of labor expertise",
Length = "2 years",
Lively = true,
LastUpdated = 1641024000,
InternationalFlag = true
;
return Okay(programs);
[HttpGet("id")]
public ActionResult GetCourse(string id)
// Dummy information for illustration
var course = new Course
Title = "Information Science",
Id = id,
ProviderId = "UNIV001",
LevelOfStudy = "Graduate",
AreasOfStudy = new Checklist "Expertise", "Statistics" ,
SubjectsOfStudy = new Checklist "Machine Studying", "Large Information", "Statistical Evaluation" ,
Particulars = "A complicated course in information science and analytics.",
EntryRequirements = "Bachelor's diploma in a quantitative subject",
Length = "2 years",
Lively = true,
LastUpdated = 1651363200,
InternationalFlag = true
;
return Okay(course);
}
}
This setup allowed me to carry out my first take a look at utilizing a Bruno consumer, and voila! I acquired my first response. Now we’re getting someplace
Safety
Earlier than delivery something, implementing safety measures was essential. I targeted on two important considerations:
- Unauthorized entry: I carried out a rough-cut API key authentication technique and added our new API pages to the robots.txt file to forestall search engine indexing. This may make it troublesome to stumble throughout our API unintentionally, and in the event that they did, they would not be capable of entry our system and not using a legitimate API key.
- Safety in opposition to DoS: To mitigate the chance of database learn operation overload (intentional or unintentional), I carried out API key price limiting together with IP price limits. I set a wise restrict of 120 requests per minute (2 requests per second) to take care of an affordable SLA whereas defending the system from unintentional request floods.
Making It a Product
Whereas I had a primary API in manufacturing, reworking it right into a priceless product required a number of further steps:
Including Enterprise Logic
We wanted to get the routes wired up so they may begin returning one thing priceless to the consumer. I used Microsoft’s Entity Framework ORM to tug data from the SQL database and map them to the API response payloads. This course of concerned creating information entry layers and implementing the mandatory enterprise logic in every controller.
Creating Providers for Reusable Logic
To advertise code reuse and preserve a clear separation of considerations, I abstracted widespread enterprise logic into companies. By the tip of the mission, I had created a number of utility companies:
Providers/
├── AuthorityFormatter.cs
├── DateFormatCalculator.cs
├── DeliveryCalculator.cs
├── DurationCalculator.cs
├── HtmlHelper.cs
├── MacronRemover.cs
├── ProviderTypeFormatter.cs
├── RegionMapper.cs
├── StreetAddressFormatter.cs
├── StringFormatter.cs
└── SubjectTaxonomyMapper.cs
Implementing Pagination
Pagination was essential for permitting third events to navigate by means of data on the API stage effectively. I created a pagination mannequin and repair:
public class ApiPaginatedResponse
public Checklist Objects get; set;
public Pagination Pagination get; set;
public class Pagination
public int Skip get; set;
public int Restrict get; set;
public int Depend get; set;
public string NextPage get; set;
public int TotalCount get; set;
Implementing Appropriate HTTP Response Codes
An typically missed however essential facet of API design is the right use of HTTP response codes. These codes present instant suggestions to API shoppers (and builders) in regards to the standing of their requests, making the API extra intuitive and simpler to work with.
I made certain to implement a variety of applicable standing codes in our API responses:
- 200 OK: For profitable GET, PUT, or PATCH requests
- 400 Dangerous Request: When the request is malformed or accommodates invalid parameters
- 401 Unauthorized: When authentication is required however not supplied or is invalid
- 403 Forbidden: When the authenticated consumer would not have permission to entry the requested useful resource
- 404 Not Discovered: When the requested useful resource would not exist
- 429 Too Many Requests: When the consumer has despatched too many requests in a given period of time (price limiting)
- 500 Inside Server Error: For surprising server errors
Customizing the UI
To boost the consumer expertise and produce our model to the API, I custom-made the Swagger UI by changing the generic branding with our brand and making use of clear, constant styling.
I additionally added instance response payloads for varied endpoints:
Swagger/
└───Examples
├───CampusExamples
│ CampusListResponseExample.cs
│ CampusResponseExample.cs
│
├───CourseExamples
│ CourseListResponseExample.cs
│ CourseResponseExample.cs
│
├───IntakeExamples
│ IntakeListResponseExample.cs
│ IntakeResponseExample.cs
│
├───ProviderExamples
│ ProviderListResponseExample.cs
│ ProviderResponseExample.cs
│
├───ScholarshipExamples
│ ScholarshipListResponseExample.cs
│ ScholarshipResponseExample.cs
│
└───StatusCodes
400ResponseExample.cs
401ResponseExample.cs
404ResponseExample.cs
429ResponseExample.cs
Provisioning API Keys
Earlier than sharing the brand new Swagger documentation, I generated and distributed API keys to the third events who could be utilizing the brand new API. This course of concerned making a safe system for producing, storing, and managing these keys.
You need not overthink this. We assigned API keys to a singleton and added code feedback to establish the related customers. This easy system allowed for straightforward administration and potential future revocation of entry if wanted.
Classes Discovered
Constructing this mission was an thrilling problem that taught me a number of priceless classes:
- Begin small and iterate: Starting with a minimal viable product and bettering it repeatedly proved to be an efficient technique.
- Outline first, then construct: Having a transparent understanding of the specified responses tremendously simplified the method of writing enterprise logic.
- Do not stress the small stuff: Getting the service into customers’ fingers shortly for suggestions is essential, even when it is not 100% polished.
- Leverage present sources: Selecting to make use of languages and frameworks already in play resulted in a extra cohesive answer and simpler future upkeep.
Future Horizons
The event of this API has not solely expanded our choices however has additionally opened up new prospects for innovation within the training sector. As extra organizations acknowledge the ability of APIs in driving development and fostering ecosystems, tasks like it will turn into more and more very important.
Whether or not you are contemplating constructing an API to your personal mission or seeking to leverage present APIs in your group, keep in mind that the journey of a thousand miles begins with a single step. Begin small, deal with delivering worth, and do not be afraid to iterate and enhance as you go.