diff --git a/broker/src/asapo_broker/database/database.go b/broker/src/asapo_broker/database/database.go
index 3a0683bf301fd3bf4b41c4d54544a1a970c3b158..9f3dd53983a2efd148777a5060f7451a5f0dfbe7 100644
--- a/broker/src/asapo_broker/database/database.go
+++ b/broker/src/asapo_broker/database/database.go
@@ -1,8 +1,7 @@
 package database
 
 type Agent interface {
-	GetNextRecord(db_name string) ([]byte, error)
-	GetRecordByID(dbname string, id int) ([]byte, error)
+	GetRecordFromDb(db_name string, op string, id int) ([]byte, error)
 	Connect(string) error
 	Close()
 	Copy() Agent
diff --git a/broker/src/asapo_broker/database/database_test.go b/broker/src/asapo_broker/database/database_test.go
index 68b1eadb44e0e5a02a19c66994a0c4cfe9540fbb..d61896433bd16fa0143f166793214767107343a7 100644
--- a/broker/src/asapo_broker/database/database_test.go
+++ b/broker/src/asapo_broker/database/database_test.go
@@ -11,10 +11,9 @@ func TestMockDataBase(t *testing.T) {
 	db.On("Connect", mock.AnythingOfType("string")).Return(nil)
 	db.On("Close").Return()
 	db.On("Copy").Return(nil)
-	db.On("GetNextRecord", "").Return([]byte(""), nil)
-	db.On("GetRecordByID", "").Return([]byte(""), nil)
+	db.On("GetRecordFromDb", "", "", 0).Return([]byte(""), nil)
+
 	db.Connect("")
-	db.GetNextRecord("")
 	db.Close()
 	db.Copy()
 	var err DBError
diff --git a/broker/src/asapo_broker/database/mock_database.go b/broker/src/asapo_broker/database/mock_database.go
index 7ac5c13188e4c498566665b57b4448963d3fbe05..81ec5978cc7fc2fb095508f340834d170e888689 100644
--- a/broker/src/asapo_broker/database/mock_database.go
+++ b/broker/src/asapo_broker/database/mock_database.go
@@ -24,12 +24,7 @@ func (db *MockedDatabase) Copy() Agent {
 	return db
 }
 
-func (db *MockedDatabase) GetNextRecord(db_name string) (answer []byte, err error) {
-	args := db.Called(db_name)
-	return args.Get(0).([]byte), args.Error(1)
-}
-
-func (db *MockedDatabase) GetRecordByID(db_name string, id int) (answer []byte, err error) {
-	args := db.Called(db_name, id)
+func (db *MockedDatabase) GetRecordFromDb(db_name string, op string, id int) (answer []byte, err error) {
+	args := db.Called(db_name, op, id)
 	return args.Get(0).([]byte), args.Error(1)
 }
diff --git a/broker/src/asapo_broker/database/mongodb.go b/broker/src/asapo_broker/database/mongodb.go
index b020d2a3a307f72778098a72beed10c1a3c8a273..9e290cf9f2f83292a8dbda095444bb2e40cb7613 100644
--- a/broker/src/asapo_broker/database/mongodb.go
+++ b/broker/src/asapo_broker/database/mongodb.go
@@ -139,6 +139,12 @@ func (db *Mongodb) createLocationPointers(dbname string) (err error) {
 	return err
 }
 
+func (db *Mongodb) setCounter(dbname string, ind int) (err error) {
+	update := bson.M{"$set": bson.M{pointer_field_name: ind}}
+	c := db.session.DB(dbname).C(pointer_collection_name)
+	return c.UpdateId(0, update)
+}
+
 func (db *Mongodb) incrementField(dbname string, max_ind int, res interface{}) (err error) {
 	update := bson.M{"$inc": bson.M{pointer_field_name: 1}}
 	change := mgo.Change{
@@ -155,7 +161,7 @@ func (db *Mongodb) incrementField(dbname string, max_ind int, res interface{}) (
 	return err
 }
 
-func (db *Mongodb) GetRecordByID(dbname string, id int) ([]byte, error) {
+func (db *Mongodb) GetRecordByID(dbname string, id int, returnID bool) ([]byte, error) {
 	var res map[string]interface{}
 	q := bson.M{"_id": id}
 	c := db.session.DB(dbname).C(data_collection_name)
@@ -167,7 +173,12 @@ func (db *Mongodb) GetRecordByID(dbname string, id int) ([]byte, error) {
 		res, _ := json.Marshal(&r)
 		log_str := "error getting record id " + strconv.Itoa(id) + " for " + dbname + " : " + err.Error()
 		logger.Debug(log_str)
-		return nil, &DBError{utils.StatusNoData, string(res)}
+		if returnID {
+			return nil, &DBError{utils.StatusNoData, string(res)}
+		} else {
+			return nil, &DBError{utils.StatusNoData, err.Error()}
+		}
+
 	}
 
 	log_str := "got record id " + strconv.Itoa(id) + " for " + dbname
@@ -248,6 +259,37 @@ func (db *Mongodb) GetNextRecord(db_name string) ([]byte, error) {
 	}
 	log_str := "got next pointer " + strconv.Itoa(curPointer.Value) + " for " + db_name
 	logger.Debug(log_str)
-	return db.GetRecordByID(db_name, curPointer.Value)
+	return db.GetRecordByID(db_name, curPointer.Value, true)
+
+}
+
+func (db *Mongodb) GetLastRecord(db_name string) ([]byte, error) {
+
+	if err := db.checkDatabaseOperationPrerequisites(db_name); err != nil {
+		return nil, err
+	}
 
+	max_ind, err := db.getMaxIndex(db_name)
+	if err != nil {
+		log_str := "error getting last pointer for " + db_name + ":" + err.Error()
+		logger.Debug(log_str)
+		return nil, err
+	}
+	res, err := db.GetRecordByID(db_name, max_ind, false)
+
+	db.setCounter(db_name, max_ind)
+
+	return res, err
+}
+
+func (db *Mongodb) GetRecordFromDb(db_name string, op string, id int) (answer []byte, err error) {
+	switch op {
+	case "next":
+		return db.GetNextRecord(db_name)
+	case "id":
+		return db.GetRecordByID(db_name, id, true)
+	case "last":
+		return db.GetLastRecord(db_name)
+	}
+	return nil, errors.New("Wrong db operation: " + op)
 }
diff --git a/broker/src/asapo_broker/database/mongodb_test.go b/broker/src/asapo_broker/database/mongodb_test.go
index 178346cfc1dfe82ed2a9b0a6b3920b034611f0a3..b5b5c18429815bc56c450990ef2db0cd798f4296 100644
--- a/broker/src/asapo_broker/database/mongodb_test.go
+++ b/broker/src/asapo_broker/database/mongodb_test.go
@@ -22,8 +22,10 @@ const dbaddress = "127.0.0.1:27017"
 
 var rec1 = TestRecord{1, "aaa"}
 var rec2 = TestRecord{2, "bbb"}
+var rec3 = TestRecord{3, "ccc"}
 var rec1_expect, _ = json.Marshal(rec1)
 var rec2_expect, _ = json.Marshal(rec2)
+var rec3_expect, _ = json.Marshal(rec3)
 
 func cleanup() {
 	db.DeleteAllRecords(dbname)
@@ -68,7 +70,6 @@ func TestMongoDBGetNextErrorWhenEmptyCollection(t *testing.T) {
 
 func TestMongoDBGetNextErrorWhenRecordNotThereYet(t *testing.T) {
 	db.Connect(dbaddress)
-	db.databases = append(db.databases, dbname)
 	defer cleanup()
 	db.InsertRecord(dbname, &rec2)
 	_, err := db.GetNextRecord(dbname)
@@ -158,7 +159,7 @@ func TestMongoDBGetRecordByID(t *testing.T) {
 	db.Connect(dbaddress)
 	defer cleanup()
 	db.InsertRecord(dbname, &rec1)
-	res, err := db.GetRecordByID(dbname, 1)
+	res, err := db.GetRecordByID(dbname, 1, true)
 	assert.Nil(t, err)
 	assert.Equal(t, string(rec1_expect), string(res))
 }
@@ -167,7 +168,62 @@ func TestMongoDBGetRecordByIDFails(t *testing.T) {
 	db.Connect(dbaddress)
 	defer cleanup()
 	db.InsertRecord(dbname, &rec1)
-	_, err := db.GetRecordByID(dbname, 2)
+	_, err := db.GetRecordByID(dbname, 2, true)
 	assert.Equal(t, utils.StatusNoData, err.(*DBError).Code)
 	assert.Equal(t, "{\"id\":2}", err.Error())
 }
+
+func TestMongoDBGetRecordNext(t *testing.T) {
+	db.Connect(dbaddress)
+	defer cleanup()
+	db.InsertRecord(dbname, &rec1)
+	res, err := db.GetRecordFromDb(dbname, "next", 0)
+	assert.Nil(t, err)
+	assert.Equal(t, string(rec1_expect), string(res))
+}
+
+func TestMongoDBGetRecordID(t *testing.T) {
+	db.Connect(dbaddress)
+	defer cleanup()
+	db.InsertRecord(dbname, &rec1)
+	res, err := db.GetRecordFromDb(dbname, "id", 1)
+	assert.Nil(t, err)
+	assert.Equal(t, string(rec1_expect), string(res))
+}
+
+func TestMongoDBWrongOp(t *testing.T) {
+	db.Connect(dbaddress)
+	defer cleanup()
+	db.InsertRecord(dbname, &rec1)
+	_, err := db.GetRecordFromDb(dbname, "bla", 0)
+	assert.NotNil(t, err)
+}
+
+func TestMongoDBGetRecordLast(t *testing.T) {
+	db.Connect(dbaddress)
+	defer cleanup()
+	db.InsertRecord(dbname, &rec1)
+	db.InsertRecord(dbname, &rec2)
+
+	res, err := db.GetRecordFromDb(dbname, "last", 0)
+	assert.Nil(t, err)
+	assert.Equal(t, string(rec2_expect), string(res))
+}
+
+func TestMongoDBGetNextAfterGetLastCorrect(t *testing.T) {
+	db.Connect(dbaddress)
+	defer cleanup()
+	db.InsertRecord(dbname, &rec1)
+	db.InsertRecord(dbname, &rec2)
+
+	res, err := db.GetRecordFromDb(dbname, "last", 0)
+	assert.Nil(t, err)
+	assert.Equal(t, string(rec2_expect), string(res))
+
+	db.InsertRecord(dbname, &rec3)
+
+	res, err = db.GetRecordFromDb(dbname, "next", 0)
+	assert.Nil(t, err)
+	assert.Equal(t, string(rec3_expect), string(res))
+
+}
diff --git a/broker/src/asapo_broker/server/get_id.go b/broker/src/asapo_broker/server/get_id.go
index f66d61970091d8429d6cc6640315563917322d1c..adffdf262ff5fc9ea157990d616e9f624ef50a4b 100644
--- a/broker/src/asapo_broker/server/get_id.go
+++ b/broker/src/asapo_broker/server/get_id.go
@@ -1,8 +1,6 @@
 package server
 
 import (
-	"asapo_common/logger"
-	"asapo_common/utils"
 	"github.com/gorilla/mux"
 	"net/http"
 	"strconv"
@@ -19,37 +17,10 @@ func extractRequestParametersID(r *http.Request) (int, bool) {
 }
 
 func routeGetByID(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	db_name, ok := extractRequestParameters(r)
-	if !ok {
-		w.WriteHeader(http.StatusBadRequest)
-		return
-	}
 	id, ok := extractRequestParametersID(r)
 	if !ok {
 		w.WriteHeader(http.StatusBadRequest)
 		return
 	}
-
-	if err := testAuth(r, db_name); err != nil {
-		writeAuthAnswer(w, "get id", db_name, err.Error())
-		return
-	}
-
-	answer, code := getRecordByID(db_name, id)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
-
-func getRecordByID(db_name string, id int) (answer []byte, code int) {
-	db_new := db.Copy()
-	defer db_new.Close()
-	statistics.IncreaseCounter()
-	answer, err := db_new.GetRecordByID(db_name, id)
-	log_str := "processing get id request in " + db_name + " at " + settings.BrokerDbAddress
-	if err != nil {
-		return returnError(err, log_str)
-	}
-	logger.Debug(log_str)
-	return answer, utils.StatusOK
+	getImage(w, r, "id", id)
 }
diff --git a/broker/src/asapo_broker/server/get_id_test.go b/broker/src/asapo_broker/server/get_id_test.go
index 0e18c932ad0f605c613dce336a1236c9dce1c6f3..dff12942c66fd9f5874e25c67669769624595612 100644
--- a/broker/src/asapo_broker/server/get_id_test.go
+++ b/broker/src/asapo_broker/server/get_id_test.go
@@ -3,8 +3,6 @@ package server
 import (
 	"asapo_broker/database"
 	"asapo_common/logger"
-	"asapo_common/utils"
-	"errors"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/suite"
@@ -46,30 +44,12 @@ func TestGetIDTestSuite(t *testing.T) {
 	suite.Run(t, new(GetIDTestSuite))
 }
 
-func (suite *GetIDTestSuite) TestGetIDWithWrongDatabaseName() {
-	suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte(""),
-		&database.DBError{utils.StatusWrongInput, ""})
-
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get id request in")))
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix)
-
-	suite.Equal(http.StatusBadRequest, w.Code, "wrong database name")
-}
-
-func (suite *GetIDTestSuite) TestGetIDWithInternalDBError() {
-	suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte(""), errors.New(""))
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get id request in")))
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix)
-	suite.Equal(http.StatusInternalServerError, w.Code, "internal error")
-}
-
-func (suite *GetIDTestSuite) TestGetIDOK() {
-	suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte("Hello"), nil)
-	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get id request in")))
+func (suite *GetIDTestSuite) TestGetIdCallsCorrectRoutine() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "id", 1).Return([]byte("Hello"), nil)
+	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get id request")))
+	ExpectCopyClose(suite.mock_db)
 
 	w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix)
-	suite.Equal(http.StatusOK, w.Code, "GetID OK")
+	suite.Equal(http.StatusOK, w.Code, "GetImage OK")
 	suite.Equal("Hello", string(w.Body.Bytes()), "GetID sends data")
 }
diff --git a/broker/src/asapo_broker/server/get_image.go b/broker/src/asapo_broker/server/get_image.go
new file mode 100644
index 0000000000000000000000000000000000000000..79f1ceaae687fe0d3deb376432d78e6e30eba8f6
--- /dev/null
+++ b/broker/src/asapo_broker/server/get_image.go
@@ -0,0 +1,60 @@
+package server
+
+import (
+	"asapo_broker/database"
+	"asapo_common/logger"
+	"asapo_common/utils"
+	"github.com/gorilla/mux"
+	"net/http"
+)
+
+func extractRequestParameters(r *http.Request) (string, bool) {
+	vars := mux.Vars(r)
+	db_name, ok := vars["dbname"]
+	return db_name, ok
+}
+
+func getImage(w http.ResponseWriter, r *http.Request, op string, id int) {
+	r.Header.Set("Content-type", "application/json")
+	db_name, ok := extractRequestParameters(r)
+	if !ok {
+		w.WriteHeader(http.StatusBadRequest)
+		return
+	}
+
+	if err := testAuth(r, db_name); err != nil {
+		writeAuthAnswer(w, "get "+op, db_name, err.Error())
+		return
+	}
+
+	answer, code := getRecord(db_name, op, id)
+	w.WriteHeader(code)
+	w.Write(answer)
+}
+
+func returnError(err error, log_str string) (answer []byte, code int) {
+	err_db, ok := err.(*database.DBError)
+	code = utils.StatusError
+	if ok {
+		code = err_db.Code
+	}
+	if code != utils.StatusNoData {
+		logger.Error(log_str + " - " + err.Error())
+	} else {
+		logger.Debug(log_str + " - " + err.Error())
+	}
+	return []byte(err.Error()), code
+}
+
+func getRecord(db_name string, op string, id int) (answer []byte, code int) {
+	db_new := db.Copy()
+	defer db_new.Close()
+	statistics.IncreaseCounter()
+	answer, err := db_new.GetRecordFromDb(db_name, op, id)
+	log_str := "processing get " + op + " request in " + db_name + " at " + settings.BrokerDbAddress
+	if err != nil {
+		return returnError(err, log_str)
+	}
+	logger.Debug(log_str)
+	return answer, utils.StatusOK
+}
diff --git a/broker/src/asapo_broker/server/get_image_test.go b/broker/src/asapo_broker/server/get_image_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cd885e7e6cb402cd8df6c4e3df08c25713310821
--- /dev/null
+++ b/broker/src/asapo_broker/server/get_image_test.go
@@ -0,0 +1,134 @@
+package server
+
+import (
+	"asapo_broker/database"
+	"asapo_common/logger"
+	"asapo_common/utils"
+	"errors"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/suite"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+)
+
+var correctTokenSuffix, wrongTokenSuffix, suffixWithWrongToken, expectedBeamtimeId string
+
+func prepareTestAuth() {
+	expectedBeamtimeId = "beamtime_id"
+	auth = utils.NewHMACAuth("secret")
+	token, err := auth.GenerateToken(&expectedBeamtimeId)
+	if err != nil {
+		panic(err)
+	}
+	correctTokenSuffix = "?token=" + token
+	wrongTokenSuffix = "?blablabla=aa"
+	suffixWithWrongToken = "?token=blabla"
+}
+
+type request struct {
+	path    string
+	cmd     string
+	answer  int
+	message string
+}
+
+func containsMatcher(substrings ...string) func(str string) bool {
+	return func(str string) bool {
+		for _, substr := range substrings {
+			if !strings.Contains(str, substr) {
+				return false
+			}
+		}
+		return true
+	}
+}
+
+func doRequest(path string) *httptest.ResponseRecorder {
+	mux := utils.NewRouter(listRoutes)
+	req, _ := http.NewRequest("GET", path, nil)
+	w := httptest.NewRecorder()
+	mux.ServeHTTP(w, req)
+	return w
+}
+
+func TestGetImageWithoutDatabaseName(t *testing.T) {
+	w := doRequest("/database/next")
+	assert.Equal(t, http.StatusNotFound, w.Code, "no database name")
+}
+
+func ExpectCopyClose(mock_db *database.MockedDatabase) {
+	mock_db.On("Copy").Return(mock_db)
+	mock_db.On("Close").Return()
+}
+
+type GetImageTestSuite struct {
+	suite.Suite
+	mock_db *database.MockedDatabase
+}
+
+func (suite *GetImageTestSuite) SetupTest() {
+	statistics.Reset()
+	suite.mock_db = new(database.MockedDatabase)
+	db = suite.mock_db
+	prepareTestAuth()
+	logger.SetMockLog()
+}
+
+func (suite *GetImageTestSuite) TearDownTest() {
+	assertExpectations(suite.T(), suite.mock_db)
+	logger.UnsetMockLog()
+	db = nil
+}
+
+func TestGetImageTestSuite(t *testing.T) {
+	suite.Run(t, new(GetImageTestSuite))
+}
+
+func (suite *GetImageTestSuite) TestGetImageWithWrongToken() {
+	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong token")))
+
+	w := doRequest("/database/" + expectedBeamtimeId + "/next" + suffixWithWrongToken)
+
+	suite.Equal(http.StatusUnauthorized, w.Code, "wrong token")
+}
+
+func (suite *GetImageTestSuite) TestGetImageWithNoToken() {
+	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract")))
+
+	w := doRequest("/database/" + expectedBeamtimeId + "/next" + wrongTokenSuffix)
+
+	suite.Equal(http.StatusUnauthorized, w.Code, "no token")
+}
+
+func (suite *GetImageTestSuite) TestGetImageWithWrongDatabaseName() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte(""),
+		&database.DBError{utils.StatusWrongInput, ""})
+
+	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request")))
+	ExpectCopyClose(suite.mock_db)
+
+	w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
+
+	suite.Equal(http.StatusBadRequest, w.Code, "wrong database name")
+}
+
+func (suite *GetImageTestSuite) TestGetImageWithInternalDBError() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte(""), errors.New(""))
+	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request")))
+	ExpectCopyClose(suite.mock_db)
+
+	w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
+	suite.Equal(http.StatusInternalServerError, w.Code, "internal error")
+}
+
+func (suite *GetImageTestSuite) TestGetImageAddsCounter() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte("Hello"), nil)
+	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request in "+expectedBeamtimeId)))
+	ExpectCopyClose(suite.mock_db)
+
+	doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
+	suite.Equal(1, statistics.GetCounter(), "GetImage increases counter")
+}
diff --git a/broker/src/asapo_broker/server/get_last.go b/broker/src/asapo_broker/server/get_last.go
new file mode 100644
index 0000000000000000000000000000000000000000..19b270b58e5968088f6a9f9155448bcd795c33bc
--- /dev/null
+++ b/broker/src/asapo_broker/server/get_last.go
@@ -0,0 +1,9 @@
+package server
+
+import (
+	"net/http"
+)
+
+func routeGetLast(w http.ResponseWriter, r *http.Request) {
+	getImage(w, r, "last", 0)
+}
diff --git a/broker/src/asapo_broker/server/get_last_test.go b/broker/src/asapo_broker/server/get_last_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..05d03460d73b503fb7cc1e2aef4979433452ab40
--- /dev/null
+++ b/broker/src/asapo_broker/server/get_last_test.go
@@ -0,0 +1,43 @@
+package server
+
+import (
+	"asapo_broker/database"
+	"asapo_common/logger"
+	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/suite"
+	"net/http"
+	"testing"
+)
+
+type GetLastTestSuite struct {
+	suite.Suite
+	mock_db *database.MockedDatabase
+}
+
+func (suite *GetLastTestSuite) SetupTest() {
+	statistics.Reset()
+	suite.mock_db = new(database.MockedDatabase)
+	db = suite.mock_db
+	prepareTestAuth()
+	logger.SetMockLog()
+}
+
+func (suite *GetLastTestSuite) TearDownTest() {
+	assertExpectations(suite.T(), suite.mock_db)
+	logger.UnsetMockLog()
+	db = nil
+}
+
+func TestGetLastTestSuite(t *testing.T) {
+	suite.Run(t, new(GetLastTestSuite))
+}
+
+func (suite *GetLastTestSuite) TestGetLastCallsCorrectRoutine() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "last", 0).Return([]byte("Hello"), nil)
+	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get last request")))
+	ExpectCopyClose(suite.mock_db)
+
+	w := doRequest("/database/" + expectedBeamtimeId + "/last" + correctTokenSuffix)
+	suite.Equal(http.StatusOK, w.Code, "GetLast OK")
+	suite.Equal("Hello", string(w.Body.Bytes()), "GetLast sends data")
+}
diff --git a/broker/src/asapo_broker/server/get_next.go b/broker/src/asapo_broker/server/get_next.go
index 5a42c3044238600655979d9919491293595c5c1a..661555bfecaa93152c39fcf96578aa6675d91908 100644
--- a/broker/src/asapo_broker/server/get_next.go
+++ b/broker/src/asapo_broker/server/get_next.go
@@ -1,60 +1,9 @@
 package server
 
 import (
-	"asapo_broker/database"
-	"asapo_common/logger"
-	"asapo_common/utils"
-	"github.com/gorilla/mux"
 	"net/http"
 )
 
-func extractRequestParameters(r *http.Request) (string, bool) {
-	vars := mux.Vars(r)
-	db_name, ok := vars["dbname"]
-	return db_name, ok
-}
-
 func routeGetNext(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	db_name, ok := extractRequestParameters(r)
-	if !ok {
-		w.WriteHeader(http.StatusBadRequest)
-		return
-	}
-
-	if err := testAuth(r, db_name); err != nil {
-		writeAuthAnswer(w, "get next", db_name, err.Error())
-		return
-	}
-
-	answer, code := getNextRecord(db_name)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
-
-func returnError(err error, log_str string) (answer []byte, code int) {
-	err_db, ok := err.(*database.DBError)
-	code = utils.StatusError
-	if ok {
-		code = err_db.Code
-	}
-	if code != utils.StatusNoData {
-		logger.Error(log_str + " - " + err.Error())
-	} else {
-		logger.Debug(log_str + " - " + err.Error())
-	}
-	return []byte(err.Error()), code
-}
-
-func getNextRecord(db_name string) (answer []byte, code int) {
-	db_new := db.Copy()
-	defer db_new.Close()
-	statistics.IncreaseCounter()
-	answer, err := db_new.GetNextRecord(db_name)
-	log_str := "processing get next request in " + db_name + " at " + settings.BrokerDbAddress
-	if err != nil {
-		return returnError(err, log_str)
-	}
-	logger.Debug(log_str)
-	return answer, utils.StatusOK
+	getImage(w, r, "next", 0)
 }
diff --git a/broker/src/asapo_broker/server/get_next_test.go b/broker/src/asapo_broker/server/get_next_test.go
index 72693797db667131bbd22b823e38b6a4b56d4e3c..04c681c61666d3418dcee1efc7ef3f7924279c25 100644
--- a/broker/src/asapo_broker/server/get_next_test.go
+++ b/broker/src/asapo_broker/server/get_next_test.go
@@ -3,67 +3,12 @@ package server
 import (
 	"asapo_broker/database"
 	"asapo_common/logger"
-	"asapo_common/utils"
-	"errors"
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/suite"
 	"net/http"
-	"net/http/httptest"
-	"strings"
 	"testing"
 )
 
-var correctTokenSuffix, wrongTokenSuffix, suffixWithWrongToken, expectedBeamtimeId string
-
-func prepareTestAuth() {
-	expectedBeamtimeId = "beamtime_id"
-	auth = utils.NewHMACAuth("secret")
-	token, err := auth.GenerateToken(&expectedBeamtimeId)
-	if err != nil {
-		panic(err)
-	}
-	correctTokenSuffix = "?token=" + token
-	wrongTokenSuffix = "?blablabla=aa"
-	suffixWithWrongToken = "?token=blabla"
-}
-
-type request struct {
-	path    string
-	cmd     string
-	answer  int
-	message string
-}
-
-func containsMatcher(substrings ...string) func(str string) bool {
-	return func(str string) bool {
-		for _, substr := range substrings {
-			if !strings.Contains(str, substr) {
-				return false
-			}
-		}
-		return true
-	}
-}
-
-func doRequest(path string) *httptest.ResponseRecorder {
-	mux := utils.NewRouter(listRoutes)
-	req, _ := http.NewRequest("GET", path, nil)
-	w := httptest.NewRecorder()
-	mux.ServeHTTP(w, req)
-	return w
-}
-
-func TestGetNextWithoutDatabaseName(t *testing.T) {
-	w := doRequest("/database/next")
-	assert.Equal(t, http.StatusNotFound, w.Code, "no database name")
-}
-
-func ExpectCopyClose(mock_db *database.MockedDatabase) {
-	mock_db.On("Copy").Return(mock_db)
-	mock_db.On("Close").Return()
-}
-
 type GetNextTestSuite struct {
 	suite.Suite
 	mock_db *database.MockedDatabase
@@ -87,45 +32,8 @@ func TestGetNextTestSuite(t *testing.T) {
 	suite.Run(t, new(GetNextTestSuite))
 }
 
-func (suite *GetNextTestSuite) TestGetNextWithWrongToken() {
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong token")))
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/next" + suffixWithWrongToken)
-
-	suite.Equal(http.StatusUnauthorized, w.Code, "wrong token")
-}
-
-func (suite *GetNextTestSuite) TestGetNextWithNoToken() {
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract")))
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/next" + wrongTokenSuffix)
-
-	suite.Equal(http.StatusUnauthorized, w.Code, "no token")
-}
-
-func (suite *GetNextTestSuite) TestGetNextWithWrongDatabaseName() {
-	suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte(""),
-		&database.DBError{utils.StatusWrongInput, ""})
-
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request")))
-	ExpectCopyClose(suite.mock_db)
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
-
-	suite.Equal(http.StatusBadRequest, w.Code, "wrong database name")
-}
-
-func (suite *GetNextTestSuite) TestGetNextWithInternalDBError() {
-	suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte(""), errors.New(""))
-	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request")))
-	ExpectCopyClose(suite.mock_db)
-
-	w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
-	suite.Equal(http.StatusInternalServerError, w.Code, "internal error")
-}
-
-func (suite *GetNextTestSuite) TestGetNextWithGoodDatabaseName() {
-	suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte("Hello"), nil)
+func (suite *GetNextTestSuite) TestGetNextCallsCorrectRoutine() {
+	suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte("Hello"), nil)
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request")))
 	ExpectCopyClose(suite.mock_db)
 
@@ -133,12 +41,3 @@ func (suite *GetNextTestSuite) TestGetNextWithGoodDatabaseName() {
 	suite.Equal(http.StatusOK, w.Code, "GetNext OK")
 	suite.Equal("Hello", string(w.Body.Bytes()), "GetNext sends data")
 }
-
-func (suite *GetNextTestSuite) TestGetNextAddsCounter() {
-	suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte("Hello"), nil)
-	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request in "+expectedBeamtimeId)))
-	ExpectCopyClose(suite.mock_db)
-
-	doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix)
-	suite.Equal(1, statistics.GetCounter(), "GetNext increases counter")
-}
diff --git a/broker/src/asapo_broker/server/listroutes.go b/broker/src/asapo_broker/server/listroutes.go
index ceee311d46043ccbaca28e037b07c4aa97457d3e..23c73d9daa12e6363ee14613cc354d293840be72 100644
--- a/broker/src/asapo_broker/server/listroutes.go
+++ b/broker/src/asapo_broker/server/listroutes.go
@@ -11,6 +11,12 @@ var listRoutes = utils.Routes{
 		"/database/{dbname}/next",
 		routeGetNext,
 	},
+	utils.Route{
+		"GetLast",
+		"Get",
+		"/database/{dbname}/last",
+		routeGetLast,
+	},
 	utils.Route{
 		"GetID",
 		"Get",
diff --git a/tests/automatic/broker/CMakeLists.txt b/tests/automatic/broker/CMakeLists.txt
index 6f1685c7d12bf036a9fa6f126b357fd962d2b954..37420e25280cc15c84dddb7d4b1159f6eab7d0b1 100644
--- a/tests/automatic/broker/CMakeLists.txt
+++ b/tests/automatic/broker/CMakeLists.txt
@@ -1,4 +1,6 @@
 add_subdirectory(get_next)
+add_subdirectory(get_last)
+
 add_subdirectory(read_config)
 
 if (UNIX)
diff --git a/tests/automatic/broker/get_last/CMakeLists.txt b/tests/automatic/broker/get_last/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4c085d239c2fcc5a38422d6ee6f8300e5cba6994
--- /dev/null
+++ b/tests/automatic/broker/get_last/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(TARGET_NAME asapo-broker)
+
+################################
+# Testing
+################################
+configure_file(${CMAKE_SOURCE_DIR}/tests/automatic/settings/broker_settings.json settings.json COPYONLY)
+configure_file(${CMAKE_SOURCE_DIR}/tests/automatic/settings/broker_secret.key broker_secret.key COPYONLY)
+
+add_script_test("${TARGET_NAME}-getlast" "$<TARGET_PROPERTY:${TARGET_NAME},EXENAME> $<TARGET_PROPERTY:asapo,EXENAME>" nomem
+        )
diff --git a/tests/automatic/broker/get_last/check_linux.sh b/tests/automatic/broker/get_last/check_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..4f0781386f675ce4f5567b3645461f7c623a0064
--- /dev/null
+++ b/tests/automatic/broker/get_last/check_linux.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+database_name=data
+
+set -e
+
+trap Cleanup EXIT
+
+Cleanup() {
+	echo cleanup
+	echo "db.dropDatabase()" | mongo ${database_name}
+	kill -9 $brokerid
+}
+
+echo "db.data.insert({"_id":2})" | mongo ${database_name}
+echo "db.data.insert({"_id":1})" | mongo ${database_name}
+
+token=`$2 token -secret broker_secret.key data`
+
+$1 -config settings.json &
+
+sleep 0.3
+brokerid=`echo $!`
+
+
+curl -v  --silent 127.0.0.1:5005/database/data/last?token=$token --stderr -
+
+curl -v  --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":2'
+curl -v  --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":2'
+
+echo "db.data.insert({"_id":3})" | mongo ${database_name}
+
+curl -v  --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":3'
+
+echo "db.data.insert({"_id":4})" | mongo ${database_name}
+
+curl -v  --silent 127.0.0.1:5005/database/data/next?token=$token --stderr - | grep '"_id":4'
+curl -v  --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":4'
\ No newline at end of file
diff --git a/tests/automatic/broker/get_last/check_windows.bat b/tests/automatic/broker/get_last/check_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..71f1a56ed36dd3b80532d460a2182cc219f208e2
--- /dev/null
+++ b/tests/automatic/broker/get_last/check_windows.bat
@@ -0,0 +1,40 @@
+SET database_name=data
+SET mongo_exe="c:\Program Files\MongoDB\Server\3.6\bin\mongo.exe"
+
+echo db.data.insert({"_id":1}) | %mongo_exe% %database_name%  || goto :error
+echo db.data.insert({"_id":2}) | %mongo_exe% %database_name%  || goto :error
+
+set full_name="%1"
+set short_name="%~nx1"
+
+"%2" token -secret broker_secret.key data > token
+set /P token=< token
+
+
+
+start /B "" "%full_name%" -config settings.json
+
+ping 1.0.0.0 -n 1 -w 100 > nul
+
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
+
+echo db.data.insert({"_id":3}) | %mongo_exe% %database_name%  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":3  || goto :error
+
+echo db.data.insert({"_id":4}) | %mongo_exe% %database_name%  || goto :error
+
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/next?token=%token% --stderr - | findstr /c:\"_id\":3  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":3  || goto :error
+
+
+goto :clean
+
+:error
+call :clean
+exit /b 1
+
+:clean
+Taskkill /IM "%short_name%" /F
+echo db.dropDatabase() | %mongo_exe% %database_name%
+del /f token
\ No newline at end of file
diff --git a/worker/api/cpp/include/worker/data_broker.h b/worker/api/cpp/include/worker/data_broker.h
index dd8eb0c794b8c0b60942c48e34635e0f540eca9e..d7eb5ed592e633af0ce1d0094a54f7e3a7aeee9f 100644
--- a/worker/api/cpp/include/worker/data_broker.h
+++ b/worker/api/cpp/include/worker/data_broker.h
@@ -40,12 +40,12 @@ class DataBroker {
       \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise.
     */
     virtual Error GetNext(FileInfo* info, FileData* data) = 0;
-  //! Receive last available image.
-  /*!
-    \param info -  where to store image metadata. Can be set to nullptr only image data is needed.
-    \param data - where to store image data. Can be set to nullptr only image metadata is needed.
-    \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise.
-  */
+    //! Receive last available image.
+    /*!
+      \param info -  where to store image metadata. Can be set to nullptr only image data is needed.
+      \param data - where to store image data. Can be set to nullptr only image metadata is needed.
+      \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise.
+    */
     virtual Error GetLast(FileInfo* info, FileData* data) = 0;
     virtual ~DataBroker() = default; // needed for unique_ptr to delete itself
 };
diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp
index 1b9d7264ce171b217a32f23c4cfd5ec59bc369aa..35a4fb096f3dc4fc0bffb1805df536b68beb2075 100644
--- a/worker/api/cpp/src/folder_data_broker.cpp
+++ b/worker/api/cpp/src/folder_data_broker.cpp
@@ -42,7 +42,7 @@ Error FolderDataBroker::CanGetData(FileInfo* info, FileData* data, uint64_t nfil
     return nullptr;
 }
 
-Error FolderDataBroker::GetFileByIndex(uint64_t nfile_to_get,FileInfo* info, FileData* data) {
+Error FolderDataBroker::GetFileByIndex(uint64_t nfile_to_get, FileInfo* info, FileData* data) {
     auto err = CanGetData(info, data, nfile_to_get);
     if (err != nullptr) {
         return err;
@@ -67,12 +67,12 @@ Error FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
     uint64_t nfile_to_get = ++current_file_;
     mutex_.unlock();
 
-    return GetFileByIndex(nfile_to_get,info,data);
+    return GetFileByIndex(nfile_to_get, info, data);
 
 }
 Error FolderDataBroker::GetLast(FileInfo* info, FileData* data) {
-    uint64_t nfile_to_get = filelist_.size()-1;
-    return GetFileByIndex(nfile_to_get,info,data);
+    uint64_t nfile_to_get = filelist_.size() - 1;
+    return GetFileByIndex(nfile_to_get, info, data);
 }
 
 }
diff --git a/worker/api/cpp/src/folder_data_broker.h b/worker/api/cpp/src/folder_data_broker.h
index a7b43f73ad5838b8e47af44606e3a6eb970895c4..cbf2005a86f67eac1c049544d6ae49cb11ad6284 100644
--- a/worker/api/cpp/src/folder_data_broker.h
+++ b/worker/api/cpp/src/folder_data_broker.h
@@ -25,7 +25,7 @@ class FolderDataBroker final : public asapo::DataBroker {
     int current_file_;
     FileInfos  filelist_;
     Error CanGetData(FileInfo* info, FileData* data, uint64_t nfile) const noexcept;
-    Error GetFileByIndex(uint64_t nfile_to_get,FileInfo* info, FileData* data);
+    Error GetFileByIndex(uint64_t nfile_to_get, FileInfo* info, FileData* data);
     std::mutex mutex_;
 };
 
diff --git a/worker/api/cpp/src/server_data_broker.cpp b/worker/api/cpp/src/server_data_broker.cpp
index 01469e35066451c45786e494e3ee348cc0951586..aff8b3dcf522e664d95f8883b8b2f6efba0d3ab6 100644
--- a/worker/api/cpp/src/server_data_broker.cpp
+++ b/worker/api/cpp/src/server_data_broker.cpp
@@ -141,19 +141,19 @@ Error ServerDataBroker::GetFileInfoFromServer(FileInfo* info, GetImageServerOper
 }
 
 Error ServerDataBroker::GetNext(FileInfo* info, FileData* data) {
-    return GetImageFromServer(GetImageServerOperation::GetNext,info,data);
+    return GetImageFromServer(GetImageServerOperation::GetNext, info, data);
 }
 
 Error ServerDataBroker::GetLast(FileInfo* info, FileData* data) {
-    return GetImageFromServer(GetImageServerOperation::GetLast,info,data);
+    return GetImageFromServer(GetImageServerOperation::GetLast, info, data);
 }
 
 std::string ServerDataBroker::OpToUriCmd(GetImageServerOperation op) {
     switch (op) {
-        case GetImageServerOperation::GetNext:
-            return "next";
-        case GetImageServerOperation::GetLast:
-            return "last";
+    case GetImageServerOperation::GetNext:
+        return "next";
+    case GetImageServerOperation::GetLast:
+        return "last";
     }
     return "";
 }
diff --git a/worker/api/cpp/src/server_data_broker.h b/worker/api/cpp/src/server_data_broker.h
index a1e6fe4bd2f3133f1692d0263c64685681258b27..cc99eb51fb47c4075c1017371f0cce965943deee 100644
--- a/worker/api/cpp/src/server_data_broker.h
+++ b/worker/api/cpp/src/server_data_broker.h
@@ -11,8 +11,8 @@ namespace asapo {
 Error HttpCodeToWorkerError(const HttpCode& code);
 
 enum class GetImageServerOperation {
-  GetNext,
-  GetLast
+    GetNext,
+    GetLast
 };
 
 class ServerDataBroker final : public asapo::DataBroker {
@@ -22,7 +22,7 @@ class ServerDataBroker final : public asapo::DataBroker {
     Error GetNext(FileInfo* info, FileData* data) override;
     Error GetLast(FileInfo* info, FileData* data) override;
 
-  void SetTimeout(uint64_t timeout_ms) override;
+    void SetTimeout(uint64_t timeout_ms) override;
     std::unique_ptr<IO> io__; // modified in testings to mock system calls,otherwise do not touch
     std::unique_ptr<HttpClient> httpclient__;
   private:
diff --git a/worker/api/cpp/unittests/test_server_broker.cpp b/worker/api/cpp/unittests/test_server_broker.cpp
index 395c3cbba8779586b243a8b10bba06b853f3b4ea..14538967a72bb6fbedce751433ad0ccc9c8978b7 100644
--- a/worker/api/cpp/unittests/test_server_broker.cpp
+++ b/worker/api/cpp/unittests/test_server_broker.cpp
@@ -119,9 +119,9 @@ TEST_F(ServerDataBrokerTests, GetLastUsesCorrectUri) {
 
     EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/last?token=" + expected_token, _,
                                         _)).WillOnce(DoAll(
-        SetArgPointee<1>(HttpCode::OK),
-        SetArgPointee<2>(nullptr),
-        Return("")));
+                                                SetArgPointee<1>(HttpCode::OK),
+                                                SetArgPointee<2>(nullptr),
+                                                Return("")));
     data_broker->GetLast(&info, nullptr);
 }