This qr code project was a pretty small and interesting chance for me to exercise everything I’ve learned about backend and frontend interactions.
One thing I learned about was fetches and async requests. I created a complicated systems of requests in order to properly compartmentalize and organize my code, but I was running into issues where the response of a fetch request wasn’t return, only a promise was. I realized that I had to fix this by using a .then() and return the fetch request itself. This told the code to wait until the fetch request goes through to
function getLink(){
return fetchId().then(obj => {
var num = Math.random()
var intervals = [];
for (var i = 0; i < obj.linkFreqs.length; i ++){
if (i == 0){
intervals.push(obj.linkFreqs[i].frequency)
}
else {
console.log(intervals)
intervals.push(intervals[i - 1] + obj.linkFreqs[i].frequency)
}
}
for (i in intervals){
console.log(num);
console.log(intervals[i])
if (num < intervals[i]){
link = obj.linkFreqs[i].link;
return link
}
}
})
}
getLink().then(link => {
console.log(link);
var head = document.querySelector('head')
var meta = document.createElement('meta')
meta.httpEquiv = "refresh"
meta.content ="0; URL=" + link;
var link = document.createElement('link')
link.rel = "canonical"
link.href = link
head.appendChild(meta)
head.appendChild(link)
})
I also learned about how to use an object we created on the backend as the request body, when sending through a request with a JSON body. For example the object and request are listed below, and the request body is specified as an object of the type QrCodeRequest, allowing us to use methods of that class (built in using spring annotations) to get the links and frequencies respectively.
@Data
public class QrCodeRequest {
private List<String> links;
private List<Double> frequencies;
}
@PostMapping("/newCode")
public ResponseEntity<QrCode> newCode(@RequestBody QrCodeRequest qrCodeRequest) {
QrCode qrCode = new QrCode();
List<String> links = qrCodeRequest.getLinks();
List<Double> frequencys = qrCodeRequest.getFrequencies();
for (int i = 0; i < links.size(); i ++){
qrCode.addLink(new LinkFreq(links.get(i), frequencys.get(i)));
}
repository.save(qrCode);
return new ResponseEntity<>(qrCode, HttpStatus.OK);
}
I also learned about some of the issues when using a class embedded in another class. For example, in the code below we can see that QrCode has a linkFreqs list which contains LinkFreq objects, which is why it’s annotated by @Embeddable. However, when you just call the QrCode object the LinkFreq object is loaded lazily, and it doesn’t have a manytomany or onetomany relationship to define the loading to not be lazy. Because of this, the LinkFreqs weren’t being passed through to the frontend when called, so instead we have to use the Hibernate.initialize(qrCode.getLinkFreqs()) function to query the qrCode which initializes the geLinkFreqs() method, meaning when it is called now the getLinkFreqs() method actually returns the links and frequencies.
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@Data
public class LinkFreq {
private String link;
private double frequency;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class QrCode {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ElementCollection
private List<LinkFreq> linkFreqs = new ArrayList<>();
public void addLink(LinkFreq linkFreq ){
linkFreqs.add(linkFreq);
return;
}
}
@GetMapping("/{id}")
@Transactional
public ResponseEntity<QrCode> getQrCode(@PathVariable long id) {
Optional<QrCode> optional = repository.findById(id);
if (optional.isPresent()) { // Good ID
QrCode qrCode = optional.get(); // value from findByID
Hibernate.initialize(qrCode.getLinkFreqs());
return new ResponseEntity<>(qrCode, HttpStatus.OK); // OK HTTP response: status code, headers, and body
}
// Bad ID
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}