Skip to content

Commit 6eaeff2

Browse files
caro3801bamthomas
andcommitted
feat: add dynamic parameter map to Context
Co-authored-by: Bruno Thomas <bthomas@icij.org>
1 parent 4bf75c5 commit 6eaeff2

File tree

4 files changed

+93
-19
lines changed

4 files changed

+93
-19
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>net.code-story</groupId>
66
<artifactId>http</artifactId>
7-
<version>2.106</version>
7+
<version>2.106-SNAPSHOT</version>
88
<packaging>jar</packaging>
99

1010
<name>CodeStory - Fluent-http</name>

src/main/java/net/codestory/http/Context.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,20 @@
1515
*/
1616
package net.codestory.http;
1717

18-
import java.io.*;
19-
import java.lang.reflect.*;
20-
import java.util.*;
21-
22-
import net.codestory.http.forms.*;
23-
import net.codestory.http.injection.*;
18+
import net.codestory.http.forms.Form;
19+
import net.codestory.http.injection.IocAdapter;
2420
import net.codestory.http.misc.Env;
25-
import net.codestory.http.security.*;
26-
import net.codestory.http.templating.*;
21+
import net.codestory.http.security.User;
22+
import net.codestory.http.templating.Site;
23+
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import java.lang.reflect.ParameterizedType;
27+
import java.lang.reflect.Type;
28+
import java.util.Collections;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Set;
2732

2833
public class Context {
2934
private final Request request;
@@ -33,6 +38,8 @@ public class Context {
3338
private final Site site;
3439
private User currentUser;
3540

41+
private Map<String, String> pathParams;
42+
3643
public Context(Request request, Response response, IocAdapter iocAdapter, Env env, Site site) {
3744
this.request = request;
3845
this.response = response;
@@ -101,6 +108,26 @@ public User currentUser() {
101108
return currentUser;
102109
}
103110

111+
// Set path params for this context (used by router).
112+
public void setPathParams(Map<String, String> pathParams) {
113+
this.pathParams = pathParams;
114+
}
115+
116+
// Get all path parameters as a map.
117+
public Map<String, String> pathParams() {
118+
return pathParams != null ? Collections.unmodifiableMap(pathParams) : Collections.emptyMap();
119+
}
120+
121+
// Get a specific path parameter by name.
122+
public String pathParam(String name) {
123+
return pathParams != null ? pathParams.get(name) : null;
124+
}
125+
126+
// Get all path parameter names.
127+
public Set<String> pathParamNames() {
128+
return pathParams != null ? Collections.unmodifiableSet(pathParams.keySet()) : Collections.emptySet();
129+
}
130+
104131
@SuppressWarnings("unchecked")
105132
public <T> T extract(Class<T> type) throws IOException {
106133
return (T) extract((Type) type);

src/main/java/net/codestory/http/routes/RouteWithPattern.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static net.codestory.http.constants.Methods.HEAD;
2020

2121
import java.util.Arrays;
22+
import java.util.Map;
2223
import java.util.Objects;
2324

2425
import net.codestory.http.Context;
@@ -53,6 +54,7 @@ public boolean matchMethod(String method) {
5354
public Object body(Context context) throws Exception {
5455
try {
5556
String[] parameters = uriParser.params(context.uri(), context.request().query());
57+
context.setPathParams(uriParser.paramsMap(context.uri(), context.request().query()));
5658
return route.body(context, parameters);
5759
} catch (Exception e) {
5860
Logs.unableToApplyRoute(context.method(), context.uri());

src/main/java/net/codestory/http/routes/UriParser.java

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import net.codestory.http.Query;
1919
import net.codestory.http.io.Strings;
2020

21+
import java.util.Arrays;
22+
import java.util.LinkedHashMap;
23+
import java.util.Map;
2124
import java.util.Objects;
2225

2326
import static java.util.Arrays.asList;
@@ -43,16 +46,7 @@ public String[] params(String uri, Query query) {
4346
String[] uriParts = parts(uri);
4447
String[] params = new String[paramsCount];
4548

46-
int index = 0;
47-
for (int i = 0; i < patternParts.length; i++) {
48-
if (patternParts[i].startsWith(":")) {
49-
if (i == patternParts.length - 1 && patternParts[i].startsWith(":") && patternParts[i].endsWith(":"))
50-
params[index++] = String.join("/", asList(uriParts).subList(i, uriParts.length));
51-
else {
52-
params[index++] = uriParts[i];
53-
}
54-
}
55-
}
49+
int index = addPathParams(uriParts, params);
5650
for (int i = 0; i < queryParamsParts.length; i++) {
5751
if (queryParamsParts[i].startsWith(":")) {
5852
params[index++] = query.get(queryParamsParts[i - 1]);
@@ -62,6 +56,57 @@ public String[] params(String uri, Query query) {
6256
return params;
6357
}
6458

59+
private int addPathParams(String[] uriParts, String[] params) {
60+
int index = 0;
61+
for (int i = 0; i < patternParts.length; i++) {
62+
if (patternParts[i].startsWith(":")) {
63+
params[index++] = paramValue(uriParts, i);
64+
}
65+
}
66+
return index;
67+
}
68+
69+
private String paramValue(String[] uriParts, int i) {
70+
if (isGreedy(i)) {
71+
return String.join("/", asList(uriParts).subList(i, uriParts.length));
72+
}
73+
return uriParts[i];
74+
}
75+
76+
private boolean isGreedy(int i) {
77+
return i == patternParts.length - 1 && patternParts[i].endsWith(":");
78+
}
79+
80+
/**
81+
* Utility to pair names and values into a map.
82+
*/
83+
public static Map<String, String> toNameValueMap(String[] names, String[] values) {
84+
Map<String, String> map = new LinkedHashMap<>();
85+
for (int i = 0; i < names.length && i < values.length; i++) {
86+
map.put(names[i], values[i]);
87+
}
88+
return map;
89+
}
90+
91+
/**
92+
* Returns the names of the path parameters in the pattern (e.g. ["index"] for /foo/:index)
93+
*/
94+
public String[] paramNames() {
95+
return Arrays.stream(patternParts)
96+
.filter(part -> part.startsWith(":"))
97+
.map(part -> part.substring(1))
98+
.toArray(String[]::new);
99+
}
100+
101+
/**
102+
* Returns a map of param name to value for the given uri and query.
103+
*/
104+
public Map<String, String> paramsMap(String uri, Query query) {
105+
String[] names = paramNames();
106+
String[] values = params(uri, query);
107+
return toNameValueMap(names, values);
108+
}
109+
65110
public boolean matches(String uri) {
66111
String[] uriParts = parts(stripQueryParams(uri));
67112
if (patternParts.length != uriParts.length && !endsWithGreedyParameter(uriPattern)) {

0 commit comments

Comments
 (0)