Skip to content

JohnMcNulty/shell-api-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation




Shell API technical test overview

AWS website deployment / Source code

Application has been deployed to AWS Amplify and is available here: https://master.d32wii2sjje0ac.amplifyapp.com/

Source code:



Assumptions

I have made an assumption from page 4 of the slides: "For each file, calculate the minimum, maximum and median values ... Distribute the data via an API based on Date (no time), Meter and Data Type”

I am assuming that this is required for each unique Date/Meter/DataType across all the data. Obviously, in the ‘real world’ I would ask for clarification on this assumption from the business sponsor.



Packages used

The following npm and nuget packages have been used:

web

Application has been created using create-react-app as a base.

  • react-bootstrap : styling
  • plotly : charting
  • moment : formatting date labels (Energy values by date chart)
  • prettier: code formatting
  • miragejs: mock API - this takes the data generated by the Shell API - dotnet core service and stores locally (see api/server.js)

dotnet core API service

  • CsvHelper : converts source flat file data to class objects
  • LinqStatistics : used for median calculation across each resultset




Web implementation

* Represent the results in a simple UI (graphs, charts or other ways)

A ReactJS app (created from create-react-app npx package runner). Application data is self contained and accessed via a mock API.

Main application components

Contains main 'connected' component (EnergyMain), calls API passes & props to child components.

Component name Purpose Comments
EnergyMain Main connected parent component Contains hook to call (mock) API on request type change (i.e. data by Date, by Energy Type, by Meter )
Handles click event from child control panel
Passes props to children
EnergyHeader Renders static header Child component
EnergyControlPanel Renders user inputs (i.e. buttons) Child component
Renders Date, Meter, Type buttons
useState hooks tracks current selection (and highlights in UI render)
Calls prop onClick func (supplied by parent component)
EnergyChart Renders data in plotly chart Child component
Component contains hook that fires call to buildChart on chartData change
Chart data is sorted, sanitized & formatted on changes to request type (see buildChart func)
buildChart accepts optional fnFormatLabel func to format x-axis labels

Other

/src/index.js

  • Creates mock api server link
  • adds bootstrap css link

/src/App.js

  • wraps main 'entry' component EnergyMain




dotnet core API service implementation

Created a dotnet core API with standard Service-Orientated-Architecture containing Service and Repository layers.

Postman collection for localhost API testing is here.

Data Layer

* Ingests data files and stores the raw data
  • In a 'real world' application with process would be handeld via an SSIS package (or similar) to load the flat files into staging tables within a database.

  • The repository layer's sole purpose is to read the raw flat files and returns a List<T> of either LpRow or TouRow objects (obviously, in the real world this dataset would come from a DB call via a stored procedure). See FlatFileDataLoaderGeneric.cs.

    • I've made this class generic to handle the variances between the 'LP...' and 'TOU...' files. Using the CsvHelper nuget package for simple reading of the files.

    • Models contain mapping helper classes (part of CsvHelper -> ClassMap nuget package) which assist with formatting dates (and generally make field mapping easier). LINK

    • FlatFileDataLoaderGeneric.cs implements the IDataLoaderGeneric interface. Therefore, another concrete implementation of this interface could be created that points to a datastore but would not affect the calling Service layer.

Service layer

* Transform the data to produce an aggregated result
  • Contains SanitizedEnergyRecords.cs that transforms raw data from List<LpRow> or List<TouRow> to a unified List (see GetMergedData()).

  • Methods to get data by request type e.g. GetDataByMeter(). These are called by the Web API layer and return a list of IList<ReportingUnit> containing the min/max/median calculations by Meter/EnergyDataType/Date.

ASP.NET Web API

* Distribute the aggregated result as an API
* Distribute the data via an API based on Date (no time), Meter and Data Type
  • EnergyRecordsController.cs contains endpoints for each required type, endpoints call service layer and returns results as JSON.
  • Startup.cs configured to dependency inject repository and service layers. Link
  • Serialization options configured to return data in camel case and remove null values from ReportingUnit objects. Link.



Caveats & Risks

In a real world application I would introduce Unit Testing, Security, Logging and more robust error handling. This solution is very bare bones and follows only a happy path!. If you would like me to introduce these features (or discuss how I would implement them) then please let me know.

About

Shell API demo

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published