Skip to content

Commit 8cecfe2

Browse files
committed
fcommons added
1 parent 01eacfc commit 8cecfe2

File tree

16 files changed

+849
-0
lines changed

16 files changed

+849
-0
lines changed

fcommons/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
**/target/**
2+
**/*.iml
3+
**/.idea/**
4+
**/.project

fcommons/fcommons-aws/pom.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>fcommons</artifactId>
7+
<groupId>com.fd</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>fcommons-aws</artifactId>
13+
<name>F-Commons AWS</name>
14+
<description>A reusable library for AWS SDK</description>
15+
16+
17+
</project>

fcommons/fcommons-model/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>fcommons</artifactId>
7+
<groupId>com.fd</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>fcommons-model</artifactId>
13+
<name>F-Commons REST</name>
14+
15+
</project>

fcommons/fcommons-rest/README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# F-Commons REST Framework
2+
## Purpose
3+
The purpose of this artifact is to handle any kind of uncaught exceptions in an HTTP Request, handle it, and
4+
return a standardized response to the client.
5+
6+
A secondary purpose is to give a easy to access request context which contains the `HttpServletRequest`,
7+
`HttpServletResponse`, and client time-zone.
8+
9+
## How To Use
10+
### Add the Maven Dependency
11+
```xml
12+
<dependency>
13+
<groupId>com.fd</groupId>
14+
<artifactId>fcommons-rest</artifactId>
15+
<version>${fcommons.version}</version>
16+
</dependency>
17+
```
18+
19+
### Extend Your Rest Controller from `FinopsifyRestController`
20+
In your Rest Controllers, just extend from `FRestController` and use its `success()` or `success(data)`
21+
methods for returning response to client.
22+
23+
```java
24+
import com.fcommons.rest.FRestController;
25+
26+
import org.springframework.http.ResponseEntity;
27+
28+
import org.springframework.web.bind.annotation.GetMapping;
29+
import org.springframework.web.bind.annotation.PathVariable;
30+
import org.springframework.web.bind.annotation.RequestMapping;
31+
import org.springframework.web.bind.annotation.RestController;
32+
33+
@RestController
34+
@RequestMapping("/account")
35+
public class AccountController extends FRestController {
36+
37+
@GetMapping("/{id}")
38+
public ResponseEntity<AwsAccount> getAccountById(@PathVariable("id") String accountId) {
39+
AwsAccount account = ...;
40+
return this.success(account);
41+
}
42+
}
43+
```
44+
45+
### Unexpected Conditions
46+
All unhandled situations will be caught and handled by the `FRestControllreAdvice`. Nothing needed to be done
47+
for this mechanism to work. It will be active as you add the dependency. Just make sure `com.fcommons` is
48+
included in your package scan.
49+
50+
With the `FRestControllerAdvice` in place:
51+
* you don't need to use try { ... } catch(...) blocks unless you'll execute a different and meaningful handling mechanism
52+
* you don't need to worry about invalid arguments or missing parameters
53+
* you can throw any type of exception from any layer for unexpected situations and don't worry about the rest. It will
54+
be caught and handled by the `FControllerAdvice` and the client will receive the message that you put into the
55+
exception.
56+
57+
58+
### Errors in the Response Body
59+
When the `FRestControllerAdvice` catches an exception, it returns an array of error items. Each error item has
60+
the following fields:
61+
* **title**: The error title
62+
* **message**: The error message
63+
* **type**: FErrorType: (Default, Object, or Field) Object and field error types are produced for invalid input
64+
parameters if you annotate your input parameters with `@Valid`. Any other type of error is considered as Default error.
65+
66+
When you put @Valid annotation to your input parameters in your endpoints, Spring MVC automatically validates that
67+
object based on the bean validation specifications that you provide in your parameter's class definition. For each
68+
validation error, the `FRestControllerAdvice` will add separate error item into the response.
69+
70+
```json
71+
{
72+
"errors": [
73+
{
74+
"title": "accountId",
75+
"message": "Invalid account id. The account id should contain exactly 12 characters",
76+
"type": "field-error"
77+
},
78+
{
79+
"title": "email",
80+
"message": "Please provide a valid e-mail address",
81+
"type": "field-error"
82+
}
83+
]
84+
}
85+
```
86+
In this response, the title of the each error item correspond to a field name of the related input parameter.
87+
88+
For the cases other than the invalid input parameter, the errors array will always contain one item which will include the
89+
thrown exception's message like below:
90+
91+
```json
92+
{
93+
"errors": [
94+
{
95+
"title": "Server error",
96+
"message": "Account not found for the given provisioning type: COST_REPORTING",
97+
"type": "default-error"
98+
}
99+
]
100+
}
101+
```
102+

fcommons/fcommons-rest/pom.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>fcommons</artifactId>
7+
<groupId>com.fd</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>fcommons-rest</artifactId>
13+
<name>F-Commons REST Framework</name>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>org.springframework.boot</groupId>
18+
<artifactId>spring-boot-starter-web</artifactId>
19+
</dependency>
20+
21+
<dependency>
22+
<groupId>com.fd</groupId>
23+
<artifactId>fcommons-util</artifactId>
24+
</dependency>
25+
26+
</dependencies>
27+
</project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.fcommons.rest;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
/**
11+
* @author fdanismaz
12+
* @since 11/26/19
13+
*/
14+
@Getter
15+
@Setter
16+
@AllArgsConstructor
17+
public class FErrorContainer {
18+
19+
private List<FErrorItem> errors;
20+
21+
public FErrorContainer() {
22+
this.errors = new ArrayList<>();
23+
}
24+
25+
public void addError(FErrorItem error) {
26+
this.errors.add(error);
27+
}
28+
29+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.fcommons.rest;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import lombok.Setter;
7+
8+
/**
9+
* @author fdanismaz
10+
* @since 11/26/19
11+
*/
12+
@Getter
13+
@Setter
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
public class FErrorItem {
17+
18+
private String title;
19+
private String message;
20+
private String type;
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.fcommons.rest;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
/**
7+
* @author fdanismaz
8+
* @since 11/26/19
9+
*/
10+
@Getter
11+
@AllArgsConstructor
12+
public enum FErrorType {
13+
14+
Default("default-error"),
15+
Object("object-error"),
16+
Field("field-error");
17+
18+
String value;
19+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.fcommons.rest;
2+
3+
import lombok.Getter;
4+
5+
/**
6+
* @author fdanismaz
7+
* @since 11/26/19
8+
*/
9+
@Getter
10+
public class FHttpException extends RuntimeException {
11+
12+
private int httpStatus;
13+
private String title;
14+
15+
public FHttpException(String title) {
16+
super(title);
17+
this.httpStatus = 500;
18+
this.title = title;
19+
}
20+
21+
public FHttpException(String title, int httpStatus) {
22+
super(title);
23+
this.httpStatus = httpStatus;
24+
this.title = title;
25+
}
26+
27+
public FHttpException(String title, String message) {
28+
super(message);
29+
this.title = title;
30+
this.httpStatus = 500;
31+
}
32+
33+
public FHttpException(String title, String message, int httpStatus) {
34+
super(message);
35+
this.title = title;
36+
this.httpStatus = httpStatus;
37+
}
38+
39+
public FHttpException(String title, String message, Throwable cause) {
40+
super(message, cause);
41+
this.httpStatus = 500;
42+
this.title = title;
43+
}
44+
45+
public FHttpException(String title, String message, Throwable cause, int httpStatus) {
46+
super(message, cause);
47+
this.httpStatus = httpStatus;
48+
this.title = title;
49+
}
50+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.fcommons.rest;
2+
3+
import org.springframework.http.ResponseEntity;
4+
import org.springframework.stereotype.Component;
5+
import org.springframework.validation.BindingResult;
6+
import org.springframework.validation.FieldError;
7+
import org.springframework.validation.ObjectError;
8+
9+
/**
10+
* @author fdanismaz
11+
* @since 11/26/19
12+
*/
13+
@Component
14+
public class FHttpResponseBuilder {
15+
16+
public ResponseEntity<ResponseEntity<?>> success() {
17+
return ResponseEntity.ok().build();
18+
}
19+
20+
public <T> ResponseEntity<T> success(T data) {
21+
return ResponseEntity.ok().body(data);
22+
}
23+
24+
public ResponseEntity<FErrorContainer> error(Exception exception, String errorTitle, int httpStatusCode) {
25+
FErrorContainer errorContainer = new FErrorContainer();
26+
errorContainer.addError(
27+
new FErrorItem(errorTitle, exception.getMessage(), FErrorType.Default.getValue()));
28+
return ResponseEntity.status(httpStatusCode).body(errorContainer);
29+
}
30+
31+
public ResponseEntity<?> error(BindingResult bindingResult, int httpStatusCode) {
32+
FErrorContainer errorContainer = new FErrorContainer();
33+
34+
for (ObjectError objectError : bindingResult.getGlobalErrors()) {
35+
FErrorItem error = new FErrorItem(objectError.getObjectName(),
36+
objectError.getDefaultMessage(), FErrorType.Object.getValue());
37+
errorContainer.addError(error);
38+
}
39+
for (FieldError fieldError : bindingResult.getFieldErrors()) {
40+
FErrorItem error = new FErrorItem(fieldError.getField(),
41+
fieldError.getDefaultMessage(), FErrorType.Field.getValue());
42+
errorContainer.addError(error);
43+
}
44+
return ResponseEntity.status(httpStatusCode).body(errorContainer);
45+
}
46+
}

0 commit comments

Comments
 (0)