API design suggestion [closed] - java

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am developing an API (library) for servers (imagine a simple server that receives a request and writes a response back on the connection).
I have a situation where I have 3 different frameworks (third party libraries). All of these provide a way to handle requests, but in their own way. Imagine the following are the interfaces to each lib:
lib A
public class AHandler implements AHandler {
public Response handle(Request req){
// ..
}
}
lib B
public class BHandler extends SomeHandler {
public BResponse handle(BRequest req){
// ..
}
}
lib C
#Handler
public class BHandler {
#HandlerMethod
public void handle(CRequest req, CResponse res){
// ..
}
}
I want to create an API that abstracts out the handle() method into some uniform way. Since A, B and C are third party, I don't have a way to modify them.
Facts:
the user can have one or more of such Handlers per server;
I can't modify the source of the third party libs and I don't want to control their releases.
What is the best way to go about API designing that can provide an uniform interface for all the three libs?

You could achieve the desired result using a combination of facade and adapters.
// defines the uniform interface exposed to API clients
interface Facade {
void handleRequest(Request request, Response response)
}
// defines the uniform interface each handler will have to expose
interface Adapter {
void handleRequest(Request request, Response response)
}
// takes a concrete adapter as argument and delegates to it for the concrete handle logic implementation
class ConcreteFacade implements Facade{
private Adapter adapter;
public ConcreteFacade(Adapter adapter){
this.adapter = adapter;
}
public void handleRequest(Request request, Response response){
adaper.handleRequest(request, response);
}
}
// one concrete adapter for each library
class ConcreteAdapter implements Adapter {
private AHandler handler;
public ConcreteAdapter(AHandler handler){
this.handler = handler;
}
public void handleRequest(Request request, Response response) {
//delegate to handler
}
}

Related

Design Pattern for multiple similar APIs in one application [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 days ago.
Improve this question
Let's say I'm working with multiple different music stream APIs. User passes me the link from one of the supported streaming services. Similar API responses should be mapped on the same application's object for further processing, but every API has unique algorithm of doing that. What's the correct way of doing that?
I came up with next solution. I'm creating an interface MusicApi, which contains methods getAppObject and isLinkMatches
public interface MusicApi {
public static AppObject getAppObject(String link);
public static boolean isLinkMatches(String link);
}
For example we're working with these APIs. Let's say they're implementing method correctly.
public class NapsterApi implements MusicApi {}
public class SpotifyApi implements MusicApi {}
public class YoutubeApi implements MusicApi {} // As example of completely different audio extraction algorithm
Now I have to choose when to use which API. I've decided to create MusicApiSelector class
(Kept implementation listing simple without using Java Reflection API or Spring #Component)
public class MusicApiSelector {
private static final MusicApi[] registeredApis = new MusicApi[]{NapsterApi, SpotifyApi, YoutubeApi};
public static MusicApi getApi(String link) {
for (MusicApi api : registeredApis) {
if (api.isLinkMatches()) {
return api;
}
}
throw new Exception("This link is not supported")
}
}
Using this should look something like this
public class Main {
public static void main(String[] args) {
String link = https://www.youtube.com/watch?v=djV11Xbc914;
MusicApi api = MusicApiSelector.getApi(link);
AppObject appObject = api.getAppObject(link);
}
}
Can you tell me if that's valid approach how this pattern is called (i guess it's Strategy Pattern). And what I can do better (maybe some completely different patterns)

how to initialize a boolean variable for every api call? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
i have an api
public interface UserService{
#GetMapping("/get-user-data")
public Response getUserData();
}
i have my impl as below
public class UserServiceImpl implements UserService{
private boolean isAuthorized = false;
public Response getUserData(User user){
//check if user is authorized
isAuthorized = isUserAuthorized()?true:false;
//perform other things based on above boolean
return someResponse;
}
}
i want this boolean "isAuthorized" must be set to false for every call to this api. whatever i have above isn't working, how to achieve this?
Instead of keeping track of the state of the boolean variable, usually we perform some action based on the positive condition:
public Response getUserData(User user){
if (isUserAuthorized()) {
// actions that should happen only when authorized
} else {
// actions that should happen only when NOT authorized
}
}
But if you really want to keep track of that state, you can always set the variable to false at the end of the method call:
//check if user is authorized
isAuthorized = isUserAuthorized()?true:false;
//perform other things based on above boolean
isAuthorized = false;
return someResponse;
Note: that may cause issues related to concurrency, but if that doesn't concern you, no harm.
if you want to call a business logic method for all api methods, you need to use a web HandlerInterceptor, by example:
#Component
public class AppInterceptor implements HandlerInterceptor {
private static Logger logger = LoggerFactory.getLogger(AppInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
var authorized = UserIsAuthorizedDummy(); // <- you business logic here
request.setAttribute("is_authorized", authorized);
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {}
private boolean UserIsAuthorizedDummy() {
return true;
}
}
And configure this interceptor with a WebMvcConfigurer implementation, by example:
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Autowired
AppInterceptor appInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(appInterceptor);
}
}
Then you can use it in you controller methods, and you will see and access the is_authorized atrribute from request object. example:
#GetMapping("/user")
public LocalResponse getUser(HttpServletRequest request) {
var response = new LocalResponse();
// check AppInterceptor.preHandle() to see when "is_authorized" attribute is set
response.setAuthorized((boolean) request.getAttribute("is_authorized"));
if (response.isAuthorized()) {
response.setUserId("1111");
}
return response;
}
#GetMapping("/profile")
public LocalResponse getProfile(HttpServletRequest request) {
var response = new LocalResponse();
// check AppInterceptor.preHandle() to see when "is_authorized" attribute is set
response.setAuthorized((boolean) request.getAttribute("is_authorized"));
if (response.isAuthorized()) {
response.setUserId("1111-22222");
}
return response;
}
You can see a working example in the following repository: https://github.com/eriknyk/springboot-web-interceptor-demo/

Calling Spring controller method without going to internet

tldr: Is there a way to make an internal request (using the method's path) without going to the internet?
--
Why do I need it? I have a project which receives many events. The decision of who will handle each event is made by a Controller. So I have something similar to this:
#RestController
#RequestMapping("/events")
public class EventHandlerAPI {
#Autowired
private EventAHandler eventAhandler;
#Autowired
private EventBHandler eventBhandler;
#PostMapping("/a")
public void handleEventA(#RequestBody EventA event) {
eventAhandler.handle(id, event);
}
#PostMapping("/b")
public void handleEventB(#RequestBody EventB event) {
eventBhandler.handle(id, event);
}
}
We recently added support to receive events through a Queue service. It sends to us the payload and the event class. Our decision is to let both interfaces working (rest and queue). The solution to avoid code duplication was to keep the Controller choosing which handler will take care of the event. The code nowadays is similar to this:
#Configuration
public class EventHandlerQueueConsumer {
#Autowired
private EventHandlerAPI eventHandlerAPI;
private Map<Class, EventHandler> eventHandlers;
#PostConstruct
public void init() {
/* start listen queue */
declareEventHandlers();
}
private void declareEventHandlers() {
eventHandlers = new HashMap<>();
eventHandlers.put(EventAHandler.class, (EventHandler<EventAHandler>) eventHandlerAPI::handleEventA);
eventHandlers.put(EventBHandler.class, (EventHandler<EventBHandler>) eventHandlerAPI::handleEventB);
}
private void onEventReceived(AbstractEvent event) {
EventHandler eventHandler = eventHandlers.get(event.getClass());
eventHandler.handle(event);
}
private interface EventHandler<T extends AbstractEvent> {
void handle(T event);
}
}
This code works, but it doesn't let the controller choose who will handle the event (our intention). The decision is actually being made by the map.
What I would like to do was to invoke the controller method through it's request mapping without going to the internet. Something like this:
#Configuration
public class EventHandlerQueueConsumer {
// MADE UP CLASS TO SHOW WHAT I WANT
#Autowired
private ControllerInkover controllerInvoker;
#PostConstruct
public void init() { /* start listen queue */ }
private void onEventReceived(AbstractEvent event) {
controllerInvoker.post(event.getPath(), new Object[] { event });
}
}
This way is much cleaner and let all the decisions be made by the controller.
I've researched a lot and didn't found a way to implement it. Debugging spring, I found how he routes the request after the DispatcherServlet, but all the spring internals uses HttpServletRequest and HttpServletResponse :(
Is there a way to make an internal request (using the method's path) without going to the internet?
They are classes of the same application
Then it should easy enough.
1) You can call your own API on http(s)://localhost:{port}/api/{path} using RestTemplate utility class. This is preferred way, since you'll follow standard MVC pattern. Something like:
restTemplate.exchange(uri, HttpMethod.POST, httpEntity, ResponseClass.class);
2) If you don't want to invoke network connection at all, then you can either use Spring's internal to find the mapping/method map or use some reflection to build custom
map upon controller's startup. Then you can pass your event/object to the method from the map in a way shown in your mock-up class. Something like:
#RequestMapping("foo")
public void fooMethod() {
System.out.println("mapping = " + getMapping("fooMethod")); // you can get all methods/mapping in #PostContruct initialization phase
}
private String getMapping(String methodName) {
Method methods[] = this.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName() == methodName) {
String mapping[] = methods[i].getAnnotation(RequestMapping.class).value();
if (mapping.length > 0) {
return mapping[mapping.length - 1];
}
}
}
return null;
}

How to maintain versions of RESTful API in Java?

I'd like to implement versioning in my RESTful web service API. I intend to put the version into the URL, viz.: /api/v3/endpoint
What is the ideal way to do this (in Java)?
Although this irritates my aversion to manual version control, my best guess is to save the API interface into a new file and include a bunch of comments to defend against too much entropy:
/** Do not leave more than 2 previous versions in existence! **/
#Path("/api/v3")
public interface RestfulAPIv3
{
int version = 3;
#Path("/resources")
#Method(GET)
public Response getResources();
}
Of course the idea would be not to copy the implementation also, but to allow it to support multiple versions. This might require moving identical signatures forward to the newer versions so no collisions would happen across interfaces in the class file:
public class RestfulAPIImpl implements RestfulAPIv3, RestfulAPIv2
{
public Response getResources()
{
List<Resource> rs = HibernateHelper.getAll(Resource.class);
// Can we do something with v2/v3 diffs here?
}
#Deprecated
public Response getOptions() // ONLY in v2!
{
return HibernateHelper.getOptions();
}
}
Thinking it through, I have no idea how we'd know which version of an endpoint the client has called, except maybe forwarding the request into the methods which is not my favorite thing.
So, my question is - what have all the versioned API implementers been doing to keep all this stuff from getting out of hand? What's the best way to do this? Am I on the right track?
(Note: this other question is about the 'if' - my question is about the 'how'.)
An alternative to not passing forward a parameter specifying the version number is to add an annotation to the method so that it automatically captures that information and saves it on a request object that can be read elsewhere.
Taking into account that your API might have requests with parameters that differ amongst versions and also have responses that look different you might have to have multiple controllers and view-model classes, one for each version of the API.
UPDATE
As per request, follows some sample code (I've used Play Framework 2.4).
So the objective is to achieve something like this in a controller class:
#Versioned(version = 0.1)
public Result postUsers() {
// get post data
UsersService service = new UsersService(getContext());
service.postUsers(postData);
// return result
}
And like this in a service class:
public class UsersService extends Service {
public UsersService(RequestContext context) {
super(context);
}
public ReturnType postUsers() {
double apiVersion = getContext().getAPIVersion();
// business logic
}
}
In order to accomplish that, you would have a Versioned annotation:
import java.lang.annotation.*;
import play.mvc.With;
#With(VersioningController.class)
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Versioned {
double version();
}
And a VersioningController:
import play.libs.F.Promise;
import play.mvc.*;
public class VersioningController extends Action<Versioned> {
public final static String API_VERSION = "version";
#Override
public Promise<Result> call(Http.Context context) throws Throwable {
context.args.put(API_VERSION, configuration.version());
return delegate.call(context);
}
}
And a RequestContext to help you manage that (you could also use the request context to manage the request timestamp, the user requesting the operation, etc):
public class RequestContext {
private double version;
public RequestContext(Double version) {
setAPIVersion(version);
}
public double getAPIVersion() {
return version;
}
public void setAPIVersion(double version) {
this.version = version;
}
}
Moreover, your controllers could have a GenericController from which they all extend:
import play.api.Play;
import play.mvc.*;
import play.mvc.Http.Request;
public abstract class GenericController extends Controller {
protected static RequestContext getContext() {
return new RequestContext(getAPIVersion());
}
protected static double getAPIVersion() {
return (double) Http.Context.current().args
.get(VersioningController.API_VERSION);
}
}
And an abstract Service from which all service classes extend:
public abstract class Service {
private RequestContext context;
public Service(RequestContext context) {
setContext(context);
}
public RequestContext getContext() {
return context;
}
public void setContext(RequestContext context) {
this.context = context;
}
}
Having all that said, keep in mind that it could be better to try to isolate the API versioning in as few layers as possible. If you can keep your business logic classes from having to manage API versions it's all the better.

Best practice: family of classes with various type of configuration class [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am defining a family of classes used to get data from different sources (from example, a class will get data from a database, another one from a file, etc.)
Since the data sources are so different, there is no common interface for their configurations.
They all share a common method getData() though.
The idea was to define a set of predefined configurations (most of the time, the configurations used will just depend on a locale, thus there would one configuration for usa, one for france, etc.).
I have create the interface:
public interface IDataSource {
public void initialize(Object config);
public List<String> getData();
}
And the class DataSourceA:
public class DataSourceA implements IDataSource {
public void initialize(Object config) {
DataSourceAConfig configA = (DataSourceAConfig) config;
initializeA(configA);
}
public List<String> getData() {
...
}
private void initializeA(DataSourceAConfig config) {
...
}
}
and DataSourceB:
public class DataSourceB implements IDataSource {
public void initialize(Object config) {
DataSourceBConfig configB = (DataSourceBConfig) config;
initializeB(configB);
}
public List<String> getData() {
...
}
private void initializeA(DataSourceBConfig config) {
...
}
}
I am not happy with that solution (for example, using initialize(Object config), then cast the config). I am looking for advice on how to rethink the problem.
Edit:
I generated the configuration implementations using jaxb. Then the user would have to pass the type of data source and the name of the configuration file to the data source factory to get the data source.
Make an interface(abstract class) like DataSourceConfig. DataSourceAConfig and DataSourceBConfig will implement(extend) it. In your initialize method, you can replace Object with DataSourceConfig.
If your datasources are so different, you should change the IDataSource too:
public interface IDataSource<T extends DataSourceConfig> {
public void initialize(T config);
public List<String> getData();
}
DataSourceConfig will be the common interface and DataSourceB will implement IDataSource like this:
public class DataSourceB implements IDataSource<DataSourceBConfig> {
public void initialize(DataSourceBConfig config) {
initializeB(config);
}
// everything else omitted for simplicity
}

Categories

Resources