SlideShare a Scribd company logo
1 of 12
Download to read offline
Creating a Facebook Clone - Part XXVI
With this last part we’ll finally finish the server code!
@Controller
@RequestMapping("/post")
@RestController
public class PostWebService {
@Autowired
private PostService posts;
@ExceptionHandler(PermissionException.class)
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(method=RequestMethod.GET, value="/list")
public List<PostDAO> postsOf(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam(name="user", required=true) String user,
@RequestParam(name="page") int page,
@RequestParam(name="size") int size) {
return posts.postsOf(auth, user, page, size);
PostWebService
PostWebService is even simpler than UserWebService as it delegates to the PostService class which is smaller.

The post service prefixes all calls with /post as opposed to the UserWebService which used /user
@Controller
@RequestMapping("/post")
@RestController
public class PostWebService {
@Autowired
private PostService posts;
@ExceptionHandler(PermissionException.class)
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(method=RequestMethod.GET, value="/list")
public List<PostDAO> postsOf(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam(name="user", required=true) String user,
@RequestParam(name="page") int page,
@RequestParam(name="size") int size) {
return posts.postsOf(auth, user, page, size);
PostWebService
This class carries a 1 to 1 relationship to the PostService class we make no use of other services
@Controller
@RequestMapping("/post")
@RestController
public class PostWebService {
@Autowired
private PostService posts;
@ExceptionHandler(PermissionException.class)
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(method=RequestMethod.GET, value="/list")
public List<PostDAO> postsOf(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam(name="user", required=true) String user,
@RequestParam(name="page") int page,
@RequestParam(name="size") int size) {
return posts.postsOf(auth, user, page, size);
PostWebService
The methods here can throw a PermissionException which as usual will translate to an ErrorDAO
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(method=RequestMethod.GET, value="/list")
public List<PostDAO> postsOf(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam(name="user", required=true) String user,
@RequestParam(name="page") int page,
@RequestParam(name="size") int size) {
return posts.postsOf(auth, user, page, size);
}
@RequestMapping(method=RequestMethod.GET, value="/feed")
public List<PostDAO> newsfeed(
@RequestHeader(name="auth", required=true) String authToken,
@RequestParam(name="page") int page,
@RequestParam(name="size") int size) {
return posts.newsfeed(authToken, page, size);
}
@RequestMapping(value="/new", method=RequestMethod.POST)
public String post(
@RequestHeader(name="auth", required=true) String auth,
PostWebService
The methods of the class translate the business logic to WebServices as before. They are trivial for the most part. List & feed just return pageable data for the given user,
notice that every method here accepts the auth header
@RequestParam(name="size") int size) {
return posts.newsfeed(authToken, page, size);
}
@RequestMapping(value="/new", method=RequestMethod.POST)
public String post(
@RequestHeader(name="auth", required=true) String auth,
@RequestBody PostDAO pd) {
return posts.post(auth, pd);
}
@RequestMapping(value="/comment", method=RequestMethod.POST)
public String comment(
@RequestHeader(name="auth", required=true) String auth,
@RequestBody CommentDAO cd) throws PermissionException {
return posts.comment(auth, cd.getPostId(), cd);
}
@RequestMapping(value="/like", method=RequestMethod.GET)
public String like(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam String postId) {
posts.like(auth, postId);
return "OK";
}
PostWebService
When making a new post or comment the DAO object is passed along with the header. This allows for clean client side code that can be unaware of the authorization for
the most part.

That's it, the class itself is a trivial wrapper around the service class!
@Controller
@RequestMapping("/media")
@RestController
public class MediaWebService {
@Autowired
private MediaService medias;
@ExceptionHandler(PermissionException.class)
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getPublicMedia(id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
MediaWebService
This brings us to the last class we will cover in the server before going back to the client… The MediaWebService. The MediaWebService is as simple as the
PostWebService but has a few gotchas due to the complexity of mime types & file upload. 

The media is mapped to the /media base URL
@Controller
@RequestMapping("/media")
@RestController
public class MediaWebService {
@Autowired
private MediaService medias;
@ExceptionHandler(PermissionException.class)
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getPublicMedia(id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
MediaWebService
Again the class can throw a `PermissionException` which will translate to an `ErrorDAO`
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getPublicMedia(id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
contentLength(av.getData().length).
body(av.getData());
}
return ResponseEntity.notFound().build();
}
@RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getAll(
@RequestHeader(name="auth", required=true) String auth,
@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getMedia(auth, id);
MediaWebService
Now that we got the main boilerplate out of the way lets look at the methods… 

This lets us fetch a public image or media file it assumes the media is public and so we need no authorization. The id of the media is passed in the URL path itself
@ResponseStatus(value=HttpStatus.FORBIDDEN)
public @ResponseBody
ErrorDAO handlePermissionException(PermissionException e) {
return new ErrorDAO(e.getMessage(), 0);
}
@RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getPublicMedia(id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
contentLength(av.getData().length).
body(av.getData());
}
return ResponseEntity.notFound().build();
}
@RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getAll(
@RequestHeader(name="auth", required=true) String auth,
@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getMedia(auth, id);
MediaWebService
We get the mime type from the media entry in the database since media can be literally anything
contentLength(av.getData().length).
body(av.getData());
}
return ResponseEntity.notFound().build();
}
@RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET)
public ResponseEntity<byte[]> getAll(
@RequestHeader(name="auth", required=true) String auth,
@PathVariable("id") String id)
throws PermissionException {
MediaDAO av = medias.getMedia(auth, id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
contentLength(av.getData().length).
body(av.getData());
}
return ResponseEntity.notFound().build();
}
@RequestMapping(method=RequestMethod.POST, value="/upload")
public @ResponseBody
String upload(
@RequestHeader(name="auth", required=true) String auth,
MediaWebService
An all request will also return a friends only media entry and is thus marked as all. Other than the auth entry it's identical to the public request
MediaDAO av = medias.getMedia(auth, id);
if(av != null) {
return ResponseEntity.ok().
contentType(MediaType.valueOf(av.getMimeType())).
contentLength(av.getData().length).
body(av.getData());
}
return ResponseEntity.notFound().build();
}
@RequestMapping(method=RequestMethod.POST, value="/upload")
public @ResponseBody
String upload(
@RequestHeader(name="auth", required=true) String auth,
@RequestParam(name="file", required=true) MultipartFile file,
@RequestParam("role") String role,
@RequestParam("visibility") String visibility)
throws IOException {
return medias.storeMedia(auth, file.getBytes(), file.
getContentType(),
role, visibility, file.getName());
}
}
MediaWebService
upload is a multipart upload request that accepts a file with additional meta data as a multipart request. 

Multipart is a part of the HTTP specification that includes a specific structure for submitting a file in a web based form. Codename One has builtin support for uploading
files using MultipartRequest so this is a pretty convenient solution for file upload.

With that we are done with the server!

This has been a lot of work for the server but most of it was simple boilerplate... The server isn't hard technically, in fact it's simple and thus a bit boring. But we had to
get through that in order to get to the more interesting pieces. The following lessons would be far more interesting as a result!

More Related Content

Similar to Creating a Facebook Clone - Part XXVI - Transcript.pdf

Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
danwrong
 
Testdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinnerTestdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinner
Truls Jørgensen
 
Appengine ja-night-sapporo#1 bt
Appengine ja-night-sapporo#1 btAppengine ja-night-sapporo#1 bt
Appengine ja-night-sapporo#1 bt
Shinichi Ogawa
 
Spca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_serviceSpca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_service
NCCOMMS
 

Similar to Creating a Facebook Clone - Part XXVI - Transcript.pdf (20)

Mashing up JavaScript
Mashing up JavaScriptMashing up JavaScript
Mashing up JavaScript
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
Creating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdfCreating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdf
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web API
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
 
Testdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinnerTestdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinner
 
Future of UI Automation testing and JDI
Future of UI Automation testing and JDIFuture of UI Automation testing and JDI
Future of UI Automation testing and JDI
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection api
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Appengine ja-night-sapporo#1 bt
Appengine ja-night-sapporo#1 btAppengine ja-night-sapporo#1 bt
Appengine ja-night-sapporo#1 bt
 
Creating an Uber Clone - Part XXIX - Transcript.pdf
Creating an Uber Clone - Part XXIX - Transcript.pdfCreating an Uber Clone - Part XXIX - Transcript.pdf
Creating an Uber Clone - Part XXIX - Transcript.pdf
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
Spca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_serviceSpca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_service
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
 
Javaone 2010
Javaone 2010Javaone 2010
Javaone 2010
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Week 12 code
Week 12 codeWeek 12 code
Week 12 code
 

More from ShaiAlmog1

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 

Creating a Facebook Clone - Part XXVI - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XXVI With this last part we’ll finally finish the server code!
  • 2. @Controller @RequestMapping("/post") @RestController public class PostWebService { @Autowired private PostService posts; @ExceptionHandler(PermissionException.class) @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(method=RequestMethod.GET, value="/list") public List<PostDAO> postsOf( @RequestHeader(name="auth", required=true) String auth, @RequestParam(name="user", required=true) String user, @RequestParam(name="page") int page, @RequestParam(name="size") int size) { return posts.postsOf(auth, user, page, size); PostWebService PostWebService is even simpler than UserWebService as it delegates to the PostService class which is smaller. The post service prefixes all calls with /post as opposed to the UserWebService which used /user
  • 3. @Controller @RequestMapping("/post") @RestController public class PostWebService { @Autowired private PostService posts; @ExceptionHandler(PermissionException.class) @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(method=RequestMethod.GET, value="/list") public List<PostDAO> postsOf( @RequestHeader(name="auth", required=true) String auth, @RequestParam(name="user", required=true) String user, @RequestParam(name="page") int page, @RequestParam(name="size") int size) { return posts.postsOf(auth, user, page, size); PostWebService This class carries a 1 to 1 relationship to the PostService class we make no use of other services
  • 4. @Controller @RequestMapping("/post") @RestController public class PostWebService { @Autowired private PostService posts; @ExceptionHandler(PermissionException.class) @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(method=RequestMethod.GET, value="/list") public List<PostDAO> postsOf( @RequestHeader(name="auth", required=true) String auth, @RequestParam(name="user", required=true) String user, @RequestParam(name="page") int page, @RequestParam(name="size") int size) { return posts.postsOf(auth, user, page, size); PostWebService The methods here can throw a PermissionException which as usual will translate to an ErrorDAO
  • 5. public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(method=RequestMethod.GET, value="/list") public List<PostDAO> postsOf( @RequestHeader(name="auth", required=true) String auth, @RequestParam(name="user", required=true) String user, @RequestParam(name="page") int page, @RequestParam(name="size") int size) { return posts.postsOf(auth, user, page, size); } @RequestMapping(method=RequestMethod.GET, value="/feed") public List<PostDAO> newsfeed( @RequestHeader(name="auth", required=true) String authToken, @RequestParam(name="page") int page, @RequestParam(name="size") int size) { return posts.newsfeed(authToken, page, size); } @RequestMapping(value="/new", method=RequestMethod.POST) public String post( @RequestHeader(name="auth", required=true) String auth, PostWebService The methods of the class translate the business logic to WebServices as before. They are trivial for the most part. List & feed just return pageable data for the given user, notice that every method here accepts the auth header
  • 6. @RequestParam(name="size") int size) { return posts.newsfeed(authToken, page, size); } @RequestMapping(value="/new", method=RequestMethod.POST) public String post( @RequestHeader(name="auth", required=true) String auth, @RequestBody PostDAO pd) { return posts.post(auth, pd); } @RequestMapping(value="/comment", method=RequestMethod.POST) public String comment( @RequestHeader(name="auth", required=true) String auth, @RequestBody CommentDAO cd) throws PermissionException { return posts.comment(auth, cd.getPostId(), cd); } @RequestMapping(value="/like", method=RequestMethod.GET) public String like( @RequestHeader(name="auth", required=true) String auth, @RequestParam String postId) { posts.like(auth, postId); return "OK"; } PostWebService When making a new post or comment the DAO object is passed along with the header. This allows for clean client side code that can be unaware of the authorization for the most part. That's it, the class itself is a trivial wrapper around the service class!
  • 7. @Controller @RequestMapping("/media") @RestController public class MediaWebService { @Autowired private MediaService medias; @ExceptionHandler(PermissionException.class) @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getPublicMedia(id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). MediaWebService This brings us to the last class we will cover in the server before going back to the client… The MediaWebService. The MediaWebService is as simple as the PostWebService but has a few gotchas due to the complexity of mime types & file upload. The media is mapped to the /media base URL
  • 8. @Controller @RequestMapping("/media") @RestController public class MediaWebService { @Autowired private MediaService medias; @ExceptionHandler(PermissionException.class) @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getPublicMedia(id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). MediaWebService Again the class can throw a `PermissionException` which will translate to an `ErrorDAO`
  • 9. @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getPublicMedia(id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). contentLength(av.getData().length). body(av.getData()); } return ResponseEntity.notFound().build(); } @RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getAll( @RequestHeader(name="auth", required=true) String auth, @PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getMedia(auth, id); MediaWebService Now that we got the main boilerplate out of the way lets look at the methods… 
 This lets us fetch a public image or media file it assumes the media is public and so we need no authorization. The id of the media is passed in the URL path itself
  • 10. @ResponseStatus(value=HttpStatus.FORBIDDEN) public @ResponseBody ErrorDAO handlePermissionException(PermissionException e) { return new ErrorDAO(e.getMessage(), 0); } @RequestMapping(value="/public/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getPublic(@PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getPublicMedia(id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). contentLength(av.getData().length). body(av.getData()); } return ResponseEntity.notFound().build(); } @RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getAll( @RequestHeader(name="auth", required=true) String auth, @PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getMedia(auth, id); MediaWebService We get the mime type from the media entry in the database since media can be literally anything
  • 11. contentLength(av.getData().length). body(av.getData()); } return ResponseEntity.notFound().build(); } @RequestMapping(value="/all/{id:.+}", method=RequestMethod.GET) public ResponseEntity<byte[]> getAll( @RequestHeader(name="auth", required=true) String auth, @PathVariable("id") String id) throws PermissionException { MediaDAO av = medias.getMedia(auth, id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). contentLength(av.getData().length). body(av.getData()); } return ResponseEntity.notFound().build(); } @RequestMapping(method=RequestMethod.POST, value="/upload") public @ResponseBody String upload( @RequestHeader(name="auth", required=true) String auth, MediaWebService An all request will also return a friends only media entry and is thus marked as all. Other than the auth entry it's identical to the public request
  • 12. MediaDAO av = medias.getMedia(auth, id); if(av != null) { return ResponseEntity.ok(). contentType(MediaType.valueOf(av.getMimeType())). contentLength(av.getData().length). body(av.getData()); } return ResponseEntity.notFound().build(); } @RequestMapping(method=RequestMethod.POST, value="/upload") public @ResponseBody String upload( @RequestHeader(name="auth", required=true) String auth, @RequestParam(name="file", required=true) MultipartFile file, @RequestParam("role") String role, @RequestParam("visibility") String visibility) throws IOException { return medias.storeMedia(auth, file.getBytes(), file. getContentType(), role, visibility, file.getName()); } } MediaWebService upload is a multipart upload request that accepts a file with additional meta data as a multipart request. Multipart is a part of the HTTP specification that includes a specific structure for submitting a file in a web based form. Codename One has builtin support for uploading files using MultipartRequest so this is a pretty convenient solution for file upload. With that we are done with the server! This has been a lot of work for the server but most of it was simple boilerplate... The server isn't hard technically, in fact it's simple and thus a bit boring. But we had to get through that in order to get to the more interesting pieces. The following lessons would be far more interesting as a result!