com.github.tonivade.zeromock.api.HttpServiceK Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2020, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.zeromock.api;
import static com.github.tonivade.purefun.Function1.fail;
import static com.github.tonivade.purefun.Matcher1.never;
import static com.github.tonivade.zeromock.api.Matchers.all;
import static com.github.tonivade.zeromock.api.Matchers.startsWith;
import static com.github.tonivade.zeromock.api.PreFilterK.filter;
import static com.github.tonivade.zeromock.api.Responses.notFound;
import static java.util.Objects.requireNonNull;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Matcher1;
import com.github.tonivade.purefun.PartialFunction1;
import com.github.tonivade.purefun.Witness;
import com.github.tonivade.purefun.instances.OptionInstances;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.type.Option;
import com.github.tonivade.purefun.type.OptionOf;
import com.github.tonivade.purefun.typeclasses.For;
import com.github.tonivade.purefun.typeclasses.Monad;
public final class HttpServiceK {
private final String name;
private final Monad monad;
private final PartialFunction1> mappings;
private final Function1>> preFilters;
private final Function1> postFilters;
public HttpServiceK(String name, Monad monad) {
this(name, monad,
PartialFunction1.of(never(), fail(IllegalStateException::new)),
request -> monad.pure(Either.right(request)),
monad::pure);
}
private HttpServiceK(String name, Monad monad,
PartialFunction1> mappings,
Function1>> preFilters,
Function1> postFilters) {
this.name = requireNonNull(name);
this.monad = requireNonNull(monad);
this.mappings = requireNonNull(mappings);
this.preFilters = requireNonNull(preFilters);
this.postFilters = requireNonNull(postFilters);
}
public String name() {
return name;
}
public HttpServiceK mount(String path, HttpServiceK other) {
requireNonNull(path);
requireNonNull(other);
return _addMapping(
startsWith(path).and(req -> other.mappings.isDefinedAt(req.dropOneLevel())),
req -> monad.map(other.execute(req.dropOneLevel()), option -> option.getOrElse(notFound())));
}
public HttpServiceK exec(RequestHandlerK handler) {
return _addMapping(all(), handler);
}
public ThenStep> when(Matcher1 matcher) {
return handler -> addMapping(matcher, handler);
}
public ThenStep> preFilter(Matcher1 matcher) {
return handler -> addPreFilter(matcher, handler);
}
public HttpServiceK preFilter(PreFilterK filter) {
return _addPreFilter(requireNonNull(filter));
}
public HttpServiceK postFilter(PostFilterK filter) {
return _addPostFilter(requireNonNull(filter));
}
public Kind> execute(HttpRequest request) {
Function1>> mappingsWithPostFilters =
mappings.andThen(value -> monad.flatMap(value, postFilters::apply)).lift();
return For.with(monad)
.then(preFilters.apply(request))
.flatMap(either -> either.fold(
res -> monad.pure(Option.some(res)),
mappingsWithPostFilters.andThen(option -> OptionInstances.traverse().sequence(monad, option))))
.map(OptionOf::narrowK)
.run();
}
public HttpServiceK combine(HttpServiceK other) {
requireNonNull(other);
return new HttpServiceK<>(
this.name + "+" + other.name,
this.monad,
this.mappings.orElse(other.mappings),
this.preFilters.andThen(
value -> monad.flatMap(value,
either -> either.fold(
response -> monad.pure(Either.left(response)), other.preFilters))),
this.postFilters.andThen(value -> monad.flatMap(value, other.postFilters))::apply
);
}
public HttpServiceK addMapping(Matcher1 matcher, RequestHandlerK handler) {
return _addMapping(matcher, handler);
}
public HttpServiceK addPreFilter(Matcher1 matcher, RequestHandlerK handler) {
return _addPreFilter(filter(monad, matcher, handler));
}
private HttpServiceK _addMapping(Matcher1 matcher, RequestHandlerK handler) {
requireNonNull(matcher);
requireNonNull(handler);
return new HttpServiceK<>(
this.name,
this.monad,
this.mappings.orElse(PartialFunction1.of(matcher, handler::apply)),
this.preFilters,
this.postFilters
);
}
private HttpServiceK _addPreFilter(PreFilterK filter) {
requireNonNull(filter);
return new HttpServiceK<>(
this.name,
this.monad,
this.mappings,
this.preFilters.andThen(
value -> monad.flatMap(value,
either -> either.fold(
response -> monad.pure(Either.left(response)), filter))),
this.postFilters
);
}
private HttpServiceK _addPostFilter(PostFilterK filter) {
requireNonNull(filter);
return new HttpServiceK<>(
this.name,
this.monad,
this.mappings,
this.preFilters,
this.postFilters.andThen(value -> monad.flatMap(value, filter))::apply
);
}
@FunctionalInterface
public interface ThenStep {
T then(RequestHandlerK handler);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy