Permalink
Browse files

Make improvements to routing

This commit makes several improvements to routing code:
- Add option to route request based on HTTP `Accept` header
- Add static routing with predicates for routing on HTTP verbs

Closes #70
  • Loading branch information...
testinfected committed Oct 9, 2017
1 parent e5fd281 commit bb721fb66b030855513639618f51fceff0a5e97a
@@ -2,6 +2,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
public final class MimeTypes {
@@ -33,7 +34,12 @@ public static MimeTypes defaults() {
}
public static boolean matches(String mediaType, String pattern) {
return MediaType.parse(pattern).isGeneralizationOf(MediaType.parse(mediaType));
return isSpecializationOf(pattern).test(mediaType);
}
public static Predicate<String> isSpecializationOf(String pattern) {
final MediaType type = MediaType.parse(pattern);
return m -> type.isGeneralizationOf(MediaType.parse(m));
}
public void register(String extension, String mimeType) {
@@ -48,7 +54,7 @@ public String guessFrom(String filename) {
}
private static class MediaType {
public static final String WILCARD = "*";
public static final String WILDCARD = "*";
public final String type;
public final String subtype;
@@ -60,12 +66,12 @@ public MediaType(String type, String subtype) {
public static MediaType parse(String mediaType) {
String[] parts = mediaType.split("/");
return parts.length > 1 ? new MediaType(parts[0], parts[1]) : new MediaType(parts[0], WILCARD);
return parts.length > 1 ? new MediaType(parts[0], parts[1]) : new MediaType(parts[0], WILDCARD);
}
public boolean isGeneralizationOf(MediaType mime) {
return (type.equals(mime.type) || type.equals(WILCARD)) &&
(subtype.equals(WILCARD) || subtype.equals(mime.subtype));
return (type.equals(mime.type) || type.equals(WILDCARD)) &&
(subtype.equals(WILDCARD) || subtype.equals(mime.subtype));
}
}
}
@@ -3,36 +3,115 @@
import com.vtence.molecule.Request;
import com.vtence.molecule.http.HttpMethod;
import java.util.function.Function;
import java.util.function.Predicate;
import static com.vtence.molecule.http.HeaderNames.ACCEPT;
import static com.vtence.molecule.http.HttpMethod.valueOf;
import static com.vtence.molecule.http.MimeTypes.isSpecializationOf;
import static com.vtence.molecule.lib.predicates.RequestWith.requestWith;
import static java.util.function.Predicate.isEqual;
public final class Predicates {
public static Predicate<Request> withPath(Predicate<? super String> path) {
return RequestWithPath.withPath(path);
public static Predicate<Request> withPath(String path) {
return withPath(isEqual(path));
}
public static Predicate<String> startingWith(String prefix) {
return StartingWith.startingWith(prefix);
public static Predicate<Request> withPathPrefix(String path) {
return withPath(test(s -> s.startsWith(path)));
}
public static Predicate<Request> withPath(Predicate<? super String> path) {
return requestWith(Request::path, path);
}
public static Predicate<Request> withMethod(String name) {
return RequestWithMethod.withMethod(name);
return withMethod(valueOf(name.toUpperCase()));
}
public static Predicate<Request> withMethod(HttpMethod method) {
return RequestWithMethod.withMethod(method);
return withMethod(isEqual(method));
}
public static Predicate<Request> withMethod(Predicate<? super HttpMethod> method) {
return RequestWithMethod.withMethod(method);
return requestWith(Request::method, method);
}
public static Predicate<Request> accepting(String mimeType) {
return accepting(isSpecializationOf(mimeType));
}
public static Predicate<Request> accepting(Predicate<? super String> mimeType) {
return requestWith(r -> r.header(ACCEPT), mimeType);
}
public static Predicate<Request> GET(String path) {
return GET(isEqual(path));
}
public static Predicate<Request> GET(Predicate<? super String> path) {
return withMethod(HttpMethod.GET).and(withPath(path));
}
public static Predicate<Request> POST(String path) {
return POST(isEqual(path));
}
public static Predicate<Request> POST(Predicate<? super String> path) {
return withMethod(HttpMethod.POST).and(withPath(path));
}
public static Predicate<Request> PUT(String path) {
return PUT(isEqual(path));
}
public static Predicate<Request> PUT(Predicate<? super String> path) {
return withMethod(HttpMethod.PUT).and(withPath(path));
}
public static Predicate<Request> PATCH(String path) {
return PATCH(isEqual(path));
}
public static Predicate<Request> PATCH(Predicate<? super String> path) {
return withMethod(HttpMethod.PATCH).and(withPath(path));
}
public static Predicate<Request> DELETE(String path) {
return DELETE(isEqual(path));
}
public static Predicate<Request> DELETE(Predicate<? super String> path) {
return withMethod(HttpMethod.DELETE).and(withPath(path));
}
public static Predicate<Request> HEAD(String path) {
return HEAD(isEqual(path));
}
public static Predicate<Request> HEAD(Predicate<? super String> path) {
return withMethod(HttpMethod.HEAD).and(withPath(path));
}
public static Predicate<Request> OPTIONS(String path) {
return OPTIONS(isEqual(path));
}
public static Predicate<Request> OPTIONS(Predicate<? super String> path) {
return withMethod(HttpMethod.OPTIONS).and(withPath(path));
}
public static <T> Predicate<T> anything() {
return t -> true;
}
public static <T> Predicate<T> all() {
return T -> true;
public static <T> Predicate<T> nothing() {
return t -> false;
}
public static <T> Predicate<T> none() {
return T -> false;
public static <T> Predicate<T> test(Function<T, Boolean> condition) {
return condition::apply;
}
Predicates() {}
@@ -0,0 +1,27 @@
package com.vtence.molecule.lib.predicates;
import com.vtence.molecule.Request;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
public class RequestWith<T> implements Predicate<Request> {
private final Function<Request, T> feature;
private final Predicate<? super T> condition;
public RequestWith(Function<Request, T> feature, Predicate<? super T> condition) {
this.feature = feature;
this.condition = condition;
}
public boolean test(Request request) {
return Predicates.<T>test(Objects::nonNull).and(condition)
.test(feature.apply(request));
}
public static <T> RequestWith<T> requestWith(Function<Request, T> feature, Predicate<? super T> matching) {
return new RequestWith<>(feature, matching);
}
}

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
@@ -12,8 +12,7 @@
import java.util.function.Predicate;
import static com.vtence.molecule.Middleware.identity;
import static com.vtence.molecule.lib.predicates.Predicates.startingWith;
import static com.vtence.molecule.lib.predicates.Predicates.withPath;
import static com.vtence.molecule.lib.predicates.Predicates.withPathPrefix;
public class FilterMap implements Middleware {
@@ -24,11 +23,11 @@ public Application then(Application next) {
}
public FilterMap map(String pathPrefix, Middleware filter) {
return map(withPath(startingWith(pathPrefix)), filter);
return map(withPathPrefix(pathPrefix), filter);
}
public FilterMap map(Predicate<? super Request> requestMatcher, Middleware filter) {
filters.put(requestMatcher, filter);
public FilterMap map(Predicate<? super Request> request, Middleware filter) {
filters.put(request, filter);
return this;
}
@@ -0,0 +1,10 @@
package com.vtence.molecule.routing;
import java.util.function.Predicate;
public interface AcceptClause extends ToClause {
ToClause accept(String mimeType);
ToClause accept(Predicate<? super String> mimeType);
}
@@ -2,26 +2,24 @@
import com.vtence.molecule.Application;
import com.vtence.molecule.Request;
import com.vtence.molecule.http.HttpMethod;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import static com.vtence.molecule.lib.predicates.Predicates.withMethod;
import static com.vtence.molecule.lib.predicates.Predicates.withPath;
public class DynamicRoute implements Route {
private final Predicate<? super String> path;
private final Predicate<? super HttpMethod> method;
private final Predicate<? super Request> otherConditions;
private final Application app;
public DynamicRoute(Predicate<? super String> path,
Predicate<? super HttpMethod> method,
Predicate<? super Request> otherConditions,
Application app) {
this.path = path;
this.method = method;
this.otherConditions = otherConditions;
this.app = app;
}
@@ -30,7 +28,7 @@ public DynamicRoute(Predicate<? super String> path,
}
private boolean matches(Request request) {
return withMethod(method).and(withPath(path)).test(request);
return withPath(path).and(otherConditions).test(request);
}
private Application extractPathParameters(Application app) {
Oops, something went wrong.

0 comments on commit bb721fb

Please sign in to comment.