AdvertiseCore is a spring based rest web server which exposes several webservices for reporting related to advertisement such as cost of advertisement, availability of Ad etc.
Data is built on static set of data.
Glossary http://www.baeldung.com/spring-boot-testing
https://spring.io/guides/gs/accessing-data-rest/
https://memorynotfound.com/spring-boot-spring-data-jpa-hibernate-h2-web-console/
=============================================== Scope and requirement ============================================================
Implement a RESTful web service that can offer reporting advertising data, part of which is extracted from a csv file and the rest being calculated as additional metrics.
- Implement only the backend and leave the creation of a colourful and flashy frontend over to the frontend developers.
- Your web service should use Java SDK 8+, Spring and Maven since we use them heavily. You can alternatively use Gradle instead of Maven if you feel more comfortable.
- Since we put quite some emphasis on tests, we would also like to see how you verify the functionality of your service by writing some tests.
- Together with the implementation, provide a short description for other developers on how to run and use your application. Run and build instructions as well as general documentation are evaluated in a positive manner, as it indicates you know how to work in that environment (spoiler alert: we love documentation!).
- We also like to see your 'long division' i.e. the working out of the problem in code, so please use a public git repository and add commits for significant working steps.
- Usage of standard JDK libraries is encouraged, though external libraries are not forbidden to use.
- Create a private git repository for your solution and send us the git bundle once done.
Find below some definitions that will allow you to better understand the business scope of the coding challenge. They are largely extracted from Appnexus wiki.
-
Advertiser: An entity that pays money to get his advertisement shown.
-
Publisher: The one who gets money for showing the ads on his site.
-
Creative: The actual graphical advertisement itself.
-
Request: In Ad Tech, it refers to a request for a creative or ad tag.
-
Demand: Advertising demand, or the desire to buy ad space and display creatives.
-
Impression: A creative served to a single user at a single point in time.
-
Revenue: The amount of money a publisher earns from ads showing.
-
Conversion: When a user makes a purchase, or performs some other desired action in response to an ad.
-
CPC: Cost per click. A payment model in which advertisers pay each time a user clicks on their advertisement.
-
CPM: Cost per mille or thousand (mille = thousand in Latin). A pricing model in which advertisers pay for every 1000 impressions of their advertisement served. This is the standard basic pricing model for online advertising.
-
CTR (%): Click-through rate. Expressed as a percentage. Literally, the ratio of users who click on a specific link to the number of total users who view an advertisement.
CTR = (clicks ÷ impressions) × 100%
-
CR (%): Conversion rate. The ratio of conversions to the number of impressions
CR = (conversions ÷ impressions) × 100%
-
Fill Rate: The ratio of impressions to the number of requests. It varies by inventory.
Fill Rate = (impressions ÷ requests) × 100%
-
ecpm: Effective Cost Per Thousand. A translation from CPM, expressed as such from a publisher's point of view.
ecpm = (revenue × 1000) ÷ impressions
In the root folder you will find two csv files which contain publisher advertising reporting data for the months of January 2018_01_report.csv and February 2018_02_report.csv. Specifically, it lists the 4 available sites of the publisher (desktop and mobile web plus android and iOS apps) broken down into five dimensions (requests, impressions, clicks, conversions and revenue (USD)).
Your task is to
-
Parse the file and store it in-memory. Kudos and additional points earned for using JPA together with any kind of underlying database technology for data persistence (mysql, derby, H2, HSQLDB etc).
-
Calculate the following additional metrics (as explained above) and also store them along with the parsed data from the CSV file:
- CTR
- CR
- Fill Rate
- ecpm
How you store them is completely up to you.
-
Design and expose a RESTful API that can read the reporting data which was parsed and generated in the previous step using the site and month as input arguments. For simplicity, we assume no reporting exists for previous years so you don't have to take the year 2018 into account.
-
Use the following keys as the input argument to map to the actual sites:
- desktop_web: "desktop web"
- mobile_web: "mobile web"
- android: "android"
- iOS: "iOS"
-
Regarding months you must provide a flexible API to accept all of the following options:
- numeric (ranging from 1-12) that map to the corresponding months (
1
forJanuary
,2
forFebruary
etc) - first 3 letters of the month (
Jan
forJanuary
,Feb
forFebruary
etc) - full name of the month (case insensitive)
- numeric (ranging from 1-12) that map to the corresponding months (
-
The API must then return a JSON object with all the following metrics defined inside the object itself:
- month
- site
- requests
- impressions
- clicks
- conversions
- revenue
- CTR
- CR
- fill_rate
- ecpm
- Assume a 2-digit precision for all double values.
- The design of the API is completely up to you. For example, you can either use PathVariable or RequestParam or a combination of the two. You can find some examples in the following section.
-
GET http://localhost:8080/reports?month=jan&site=desktop_mobile
or
GET http://localhost:8080/reports/jan/desktop_mobile
or
GET http://localhost:8080/reports/jan?site=desktop_mobile
JSON Response:
{ "month" : "January", "site" : "desktop web", "requests" : "some_value", "impressions" : "some_value", "clicks" : "some_value", "conversions" : "some_value", "revenue" : "some_value", "CTR" : "some_value", "CR" : "some_value", "fill_rate" : "some_value", "ecpm" : "some_value" } ```
-
GET http://localhost:8080/reports?month=2&site=ios JSON Response:
{ "month" : "February", "site" : "iOS", "requests" : "some_value", "impressions" : "some_value", "clicks" : "some_value", "conversions" : "some_value", "revenue" : "some_value", "CTR" : "some_value", "CR" : "some_value", "fill_rate" : "some_value", "ecpm" : "some_value" } ```
-
Extra points (not mandatory) if you support aggregate reports like
- GET http://localhost:8080/reports?month=january The JSON Response will contain the metrics for January for all sites (notice the absence of "site" attribute):
{ "month" : "January", "requests" : "some_value", "impressions" : "some_value", "clicks" : "some_value", "conversions" : "some_value", "revenue" : "some_value", "CTR" : "some_value", "CR" : "some_value", "fill_rate" : "some_value", "ecpm" : "some_value" }
- GET http://localhost:8080/reports?site=android The JSON response will contain the metrics for the android site for all months (notice the absence of "month" attribute):
{ "site" : "android", "requests" : "some_value", "impressions" : "some_value", "clicks" : "some_value", "conversions" : "some_value", "revenue" : "some_value", "CTR" : "some_value", "CR" : "some_value", "fill_rate" : "some_value", "ecpm" : "some_value" }
The above examples are just for guidance, feel free to follow them but don't hesitate to come up with your own approach.
Good luck!