How to include a thrift file from a different micro service - microservices

I am new to micro service and thrift world, I wonder how to include a thrift file from a different micro service.
ex:
In my user micro service, I have
namespace go user
struct User {
1: required string id;
2: required string email;
3: required string password;
4: optional list<Order> roles;
}
and in my order micro service, I have
namespace go order
struct Order {
1: required string id;
2: required string orderNumber;
}
if I also want my User struct to have a list of Order, how do I include it from my order micro service?
Thanks

You need to include the file, the reference the type with the included prefix, like so:
namespace go user
include "order.thrift"
struct User {
1: required string id;
2: required string email;
3: required string password;
4: optional list<order.Order> roles;
}
Recommended read: https://thrift.apache.org/docs/idl.html, escpecially this example

Related

How to handle post and put request data validation

I have following user details model that is used in POST & PUT controllers of /user resource.
public class UserDetails {
#NotBlank
private String username;
#NotBlank
private String password;
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#NotBlank
private String nic;
#NotNull
private Integer roleId;
// constructor & getters setters
}
#PostMapping("/org/employee")
public void createEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.createUser(empDetails);
}
#PutMapping("/org/employee")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.updateUser(empDetails);
}
Here, UserDetails has #NotNull & #NotBlank validations. POST would work fine because to create a user, all details are mandatory. But when updating with PUT, I don't need all properties of UserDetails to be filled.
So my questions are,
How this kind of scenarios are handled? Do we usually force clients to send all those details whether they are changed or not?
Is it possible to disable request body validation just for a particular endpoint or do I have to create separate model that looks the same but without validations?
Seeing your post I can infer that you are interested in modifying the resource
Well to do this you should to use PATCH method instead of PUT.
In PUT you need to send the entire data since it is intended for replacing the resource which is not in the case of the PATCH.
Well in case of the PUT or PATCH we need to ensure that we have an existing resource. Hence before saving it is necessary that we get the original resource from the data store. Then we can modify it with the help of the validation rules on the Entity itself.
so your code should be like.
Considering you have a repository class named as
EmployeeRepository
#PutMapping("/org/employee/{id}")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails, #PathVariable("id") int id) {
Optional<Employee> emp = employeeRepo.findById(id);
if (emp.isPresent()) {
// update the new values using setters
// Finally update the resource.
employeeService.updateUser(empDetails);
} else {
throw new ResourceNotFoundException("Your custom msg");
}
}
The repository code should be placed inside the service method ie updateUser but I have placed it here just for demonstration.

Thrift file how to define a list of object id

I am using thrift + Go, and my thrift file looks like this:
namespace go user
struct Role {
1: string id;
2: string roleName;
}
struct User {
1: required string id;
2: required string email;
3: required string password;
4: required string name;
5: optional list<Role.id> roles;
}
when I run : thrift -r --gen go user.thrift
I got:
Type "Role.id" not defined
Any ideas on how I should achieve this?
Role.id is not a data type
struct User {
1: required string id;
2: required string email;
3: required string password;
4: required string name;
5: optional list<string> roles;
}
Side notes:
set<string> might be a better choice for roles ids
regarding required: I strongly suggest to read this comprehensive summary first, which has a whole section about that topic.

Spring data mongodb #DBRef list

I am trying to have a list in a model using #DBRef but I can't get it to work.
This is my User model:
#Data
#Document
public class User {
#Id
#JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
#Indexed(unique = true)
#NotBlank
private String email;
#NotBlank
private String name;
#NotBlank
private String password;
#DBRef
private List<Server> servers;
}
Server model:
#Data
#Document
public class Server {
#Id
#JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
#NotBlank
private String name;
#NotBlank
private String host;
}
The structure is very simple, every user can have multiple servers. But when I add servers to the user the server is created, but the servers array contains one null entry("servers" : [ null ]). So the server isn't added to the user. This is how I create a server and add it to an user:
#PostMapping
public Mono create(#Valid #RequestBody Server server, Mono<Authentication> authentication) {
return this.serverRepository.save(server).then(authentication.flatMap(value -> {
User user = (User) value.getDetails();
user.getServers().add(server);
return userRepository.save(user);
})).map(value -> server);
}
So I simply create and save a server, add the server the user and then save the user. But it doesn't work. I keep having an array with one null entry.
I've seen this page: http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb. But it is for saving the child document, not for linking it. Also it is for a single document, not for an array or list.
Why is my list not being saved correctly?
All my libraries are coming from spring boot version 2.0.0.M6.
UPDATE
When removing #DBRef from the user's servers property the servers are getting saved, but they of course get double created, in the server collection and in every user.servers. So the error has something to do with references.
After some googling I found the answer...
https://jira.spring.io/browse/DATAMONGO-1583
https://jira.spring.io/browse/DATAMONGO-1584
Reactive mongo doesn't support this.
Actually there is a way to resolve DbRefs without to using the blocking driver. Yes - the references are resolved in a blocking fashion, but does not require a second connection. In order to achieve this we have to write our own DbRefResolver: NbDbRefResolver.java. In the provided resolver there is a flag: RESOLVE_DB_REFS_BY_ID_ONLY. If is switched on will not going to resolve the DbRefs from the database, but instead will resolve them to fake objects with id only. It is up to implementation to fill the references later in non-blocking fashion.
If the flag RESOLVE_DB_REFS_BY_ID_ONLY is set to false it will eagerly resolve the references by using the non-blocking driver, but will block the execution until the references are resolved.
Here is how to register the DbRefResolver in the app: DbConfig.kt
Files attached are provided here: https://jira.spring.io/browse/DATAMONGO-1584
Me did it like that for roles :
#Unwrapped(onEmpty = Unwrapped.OnEmpty.USE_NULL)
private Collection<Role> roles;
you can check the doc (2021) here : https://spring.io/blog/2021/04/20/what-s-new-in-spring-data-2021-0

Security filtering entity collection with jax-rs and jersey

I've been looking around on how to filter results based on certain security roles. I've been looking at filters but this just seems to filter out certain fields rather than the complete entity itself. Let me try to explain what I need. Lets say I have 2 entity classes:
public class Project {
private Long id;
private String name;
private String description;
// getters and setters
}
public class User {
private Long id;
private String name;
private String email;
// getters and setters
}
resource:
#Path("projects")
#Produces("application/json")
public class ProjectsResource {
#GET
public List<Project> getProjects() {
return getDetailedProjects();
}
}
Also I have 2 companies, each with their own projects. For convenience lets call them company A and company B.
What I would like to achieve is that 3 users all using this same resource get different results based on their security role.
User 1: the Super user, should get everything
User 2: manager for company A, should only get projects for company A
User 3: manager for company B, should only get projects for company B
How should I go about doing this? It just doesn't seem right to do this filtering in each resource.
I'm using jax-rs, with role based security. Users are linked to a role which grants them access to projects for a specific company.
I think you would have to parameterize your getDetailedProjectsmethod with the accessing user.
To achieve that you can inject the jersey SecurityContextinto your Resource like so (from jersey documentation):
#Path("basket")
public ShoppingBasketResource get(#Context SecurityContext sc) {
if (sc.isUserInRole("PreferredCustomer") {
return new PreferredCustomerShoppingBasketResource();
} else {
return new ShoppingBasketResource();
}
}
The securityContext.getUserPrincipal().getName()method will allow you to get hold of the requesting user and map that to a method parameter (or use it plain).

Cannot implicitly convert type 'string' to Model

I keep getting these errors:
Error 1 Cannot implicitly convert type 'string' to 'NSWebSite.Models.Role'
public Role GetRoleForUser (User user)
{
if (!UserExists(user))
throw new ArgumentException(MissingUser);
return user.Roles.TargetRoleName;
}
Error 2 'NSWebSite.Models.User' does not contain a definition for 'RoleID'
User newUser = new User()
{
Name = name,
Password = FormsAuthentication.HashPasswordForStoringInConfigFile(
password.Trim(), "md5"),
Email = email,
RoleID = role.Id
};
Error 1 - I have no idea how to fix, so any advice is welcome.
Error 2 - I am getting it because my user model does not contain the definition for RoleID. If I want to set the role when I create a new user, what should I put here instead?
Below is my repository file (modified from here: brianleggDOTcom/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx) - DOT=. (dam antispam measures :-) )
http://www.mediafire.com/?gey4y9ub0v2u9nh
and my Model.Designer.cs file
http://www.mediafire.com/?qa3p9we8uqwfj09
Your Error #2 simply means that your User class has no definition for a RoleID property. Look at the class definition and you can define it there.
Your Error #1 looks like you have a method with a return type of Role, and you're trying to do:
return user.Roles.TargetRoleName; // this is a string???
If that string is what you do want to return, you'll need to modify your method like so:
string YourMethodName(...any parameters you have...)
{
// ...your code here
return SomeRole;
}
Or you can change your TargetRoleName property from type string to Role.
My first question would be: Why is this all in the same class?
I would start by sorting the classes: Role, User, etc.
You need to define what a Role is and what a User is, separately.
public class User {
private String name;,
private String password;
private String email;
private RoleID role;
public User(String name, String password, String email, RoleID role) {
this.name = name;
this.password = password;
this.email = email;
this.role = role;
}
public void someOtherMethod() {
//some code here, etc
}
}
I am kinda new to this part of MVC and C#, from the original example at: https://www.brianlegg.com/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx
I had changed the DB schema from a 1 to many for user and roles to a many to many relationship. Changing the DB scheme back and updating the entity schema made everything work again like from the original blog post.
Why the original poster did not separate the two classes I am not sure, but once I get things working like I want I will start looking at cleaning up the code. If some one has any suggestions about how to make the example from the above mentioned webpage work with a many to many relationship for the User and Roles, they will be greatly appreciated :-)

Resources